refactor Record type

This commit is contained in:
vms 2020-08-13 21:02:23 +03:00
parent 458adc2534
commit eb11794240
17 changed files with 306 additions and 107 deletions

View File

@ -1,6 +1,6 @@
//! Parse the WIT binary representation into an [AST](crate::ast).
use crate::{ast::*, interpreter::Instruction, types::*, vec1::Vec1};
use crate::{ast::*, interpreter::Instruction, types::*};
use nom::{
error::{make_error, ErrorKind, ParseError},
Err, IResult,
@ -70,6 +70,25 @@ fn uleb<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'i
))
}
fn record_field<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], RecordFieldType, E> {
if input.is_empty() {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}
consume!((input, name) = string(input)?);
consume!((input, ty) = ty(input)?);
Ok((
input,
RecordFieldType {
name: name.to_owned(),
ty,
},
))
}
/// Parse an interface type.
fn ty<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
@ -97,9 +116,9 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
0x0c => InterfaceType::I32,
0x0d => InterfaceType::I64,
0x0e => {
consume!((input, record_type) = record_type(input)?);
consume!((input, record_name) = string(input)?);
InterfaceType::Record(record_type)
InterfaceType::Record(record_name.to_owned())
}
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
};
@ -111,11 +130,15 @@ fn ty<'input, E: ParseError<&'input [u8]>>(
fn record_type<'input, E: ParseError<&'input [u8]>>(
input: &'input [u8],
) -> IResult<&'input [u8], RecordType, E> {
let (output, fields) = list(input, ty)?;
use crate::vec1::Vec1;
let (output, name) = string(input)?;
let (output, fields) = list(output, record_field)?;
Ok((
output,
RecordType {
name: name.to_owned(),
fields: Vec1::new(fields).expect("Record must have at least one field, zero given."),
},
))
@ -240,6 +263,7 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
0x38 => (input, Instruction::ByteArrayLowerMemory),
0x39 => (input, Instruction::ByteArraySize),
/*
0x25 => {
consume!((input, argument_0) = uleb(input)?);
@ -260,6 +284,7 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
},
)
}
*/
0x3A => {
consume!((input, argument_0) = uleb(input)?);
@ -832,8 +857,11 @@ mod tests {
Instruction::StringLiftMemory,
Instruction::StringLowerMemory,
Instruction::StringSize,
/*
Instruction::RecordLift { type_index: 1 },
Instruction::RecordLower { type_index: 1 },
*/
],
));

View File

@ -154,17 +154,25 @@ impl Parse<'_> for RecordType {
fn parse(parser: Parser<'_>) -> Result<Self> {
parser.parse::<keyword::record>()?;
parser.parse::<keyword::string>()?;
let record_name = parser.parse()?;
let mut fields = vec![];
while !parser.is_empty() {
fields.push(parser.parens(|parser| {
parser.parse::<keyword::field>()?;
parser.parse::<keyword::string>()?;
let name = parser.parse()?;
parser.parse()
parser.parse::<keyword::field>()?;
let ty = parser.parse()?;
Ok(RecordFieldType { name, ty })
})?);
}
Ok(RecordType {
name: record_name,
fields: Vec1::new(fields).expect("Record must have at least one field, zero given."),
})
}
@ -339,7 +347,9 @@ impl<'a> Parse<'a> for Instruction {
parser.parse::<keyword::byte_array_size>()?;
Ok(Instruction::ByteArraySize)
} else if lookahead.peek::<keyword::record_lift>() {
}
/*
else if lookahead.peek::<keyword::record_lift>() {
parser.parse::<keyword::record_lift>()?;
Ok(Instruction::RecordLift {
@ -351,7 +361,9 @@ impl<'a> Parse<'a> for Instruction {
Ok(Instruction::RecordLower {
type_index: parser.parse()?,
})
} else if lookahead.peek::<keyword::record_lift_memory>() {
}
*/
else if lookahead.peek::<keyword::record_lift_memory>() {
parser.parse::<keyword::record_lift_memory>()?;
Ok(Instruction::RecordLiftMemory {
@ -857,8 +869,10 @@ mod tests {
Instruction::StringLiftMemory,
Instruction::StringLowerMemory,
Instruction::StringSize,
/*
Instruction::RecordLift { type_index: 42 },
Instruction::RecordLower { type_index: 42 },
*/
];
assert_eq!(inputs.len(), outputs.len());

View File

@ -111,18 +111,30 @@ where
InterfaceType::I64 => 0x0d_u8.to_bytes(writer),
InterfaceType::Record(record_type) => {
0x0e_u8.to_bytes(writer)?;
record_type.to_bytes(writer)
record_type.as_str().to_bytes(writer)
}
}
}
}
/// Encode a `RecordType` into bytes.
impl<W> ToBytes<W> for RecordFieldType
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
self.name.as_str().to_bytes(writer)?;
self.ty.to_bytes(writer)
}
}
/// Encode a `RecordType` into bytes.
impl<W> ToBytes<W> for RecordType
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
self.name.as_str().to_bytes(writer)?;
self.fields.to_bytes(writer)
}
}
@ -338,7 +350,7 @@ where
Instruction::ByteArrayLiftMemory => 0x37_u8.to_bytes(writer)?,
Instruction::ByteArrayLowerMemory => 0x38_u8.to_bytes(writer)?,
Instruction::ByteArraySize => 0x39_u8.to_bytes(writer)?,
/*
Instruction::RecordLift { type_index } => {
0x25_u8.to_bytes(writer)?;
(*type_index as u64).to_bytes(writer)?
@ -347,6 +359,7 @@ where
0x26_u8.to_bytes(writer)?;
(*type_index as u64).to_bytes(writer)?
}
*/
Instruction::RecordLiftMemory { type_index } => {
0x3A_u8.to_bytes(writer)?;
(*type_index as u64).to_bytes(writer)?

View File

@ -85,13 +85,18 @@ impl ToString for &InterfaceType {
impl ToString for &RecordType {
fn to_string(&self) -> String {
format!(
"record{fields}",
"record {} {fields}",
self.name,
fields = self
.fields
.iter()
.fold(String::new(), |mut accumulator, interface_type| {
.fold(String::new(), |mut accumulator, field_type| {
accumulator.push(' ');
accumulator.push_str(&format!("(field {})", &interface_type.to_string()));
accumulator.push_str(&format!(
"{}: {}\n",
field_type.name,
(&field_type.ty).to_string()
));
accumulator
}),
)
@ -142,8 +147,10 @@ impl ToString for &Instruction {
Instruction::ByteArrayLiftMemory => "byte_array.lift_memory".into(),
Instruction::ByteArrayLowerMemory => "byte_array.lower_memory".into(),
Instruction::ByteArraySize => "byte_array.size".into(),
/*
Instruction::RecordLift { type_index } => format!("record.lift {}", type_index),
Instruction::RecordLower { type_index } => format!("record.lower {}", type_index),
*/
Instruction::RecordLiftMemory { type_index } => {
format!("record.lift_memory {}", type_index)
}
@ -475,8 +482,10 @@ mod tests {
(&Instruction::StringLiftMemory).to_string(),
(&Instruction::StringLowerMemory).to_string(),
(&Instruction::StringSize).to_string(),
/*
(&Instruction::RecordLift { type_index: 42 }).to_string(),
(&Instruction::RecordLower { type_index: 42 }).to_string(),
*/
];
let outputs = vec![
"arg.get 7",

View File

@ -1,6 +1,7 @@
//! The error module contains all the data structures that represent
//! an error.
use crate::values::InterfaceValue;
use crate::{ast::TypeKind, interpreter::Instruction, types::InterfaceType};
use std::{
error::Error,
@ -21,7 +22,7 @@ pub type InterpreterResult<T> = Result<T, InstructionError>;
#[derive(Debug)]
pub struct WasmValueNativeCastError {
/// The initial type.
pub from: InterfaceType,
pub from: InterfaceValue,
/// The targeted type.
///
@ -98,7 +99,7 @@ pub enum InstructionErrorKind {
expected_type: InterfaceType,
/// The received type.
received_type: InterfaceType,
received_value: InterfaceValue,
},
/// Need to read some values from the stack, but it doesn't
@ -163,6 +164,12 @@ pub enum InstructionErrorKind {
type_index: u32,
},
/// The searched by name type doesn't exist.
RecordTypeByNameIsMissing {
/// The record type name.
type_name: String,
},
/// Read a type that has an unexpected type.
InvalidTypeKind {
/// The expected kind.
@ -199,11 +206,11 @@ impl Display for InstructionErrorKind {
Self::InvalidValueOnTheStack {
expected_type,
received_type,
received_value,
} => write!(
formatter,
"read a value of type `{:?}` from the stack, but the type `{:?}` was expected",
received_type, expected_type,
"read a value `{:?}` from the stack, that can't be converted to `{:?}`",
received_value, expected_type,
),
Self::StackIsTooSmall { needed } => write!(
@ -261,6 +268,12 @@ impl Display for InstructionErrorKind {
"read a type of kind `{:?}`, but the kind `{:?}` was expected",
received_kind, expected_kind
),
Self::RecordTypeByNameIsMissing { type_name } => write!(
formatter,
"type with `{}` is missing in a Wasm binary",
type_name
),
Self::SerdeError(err) => write!(
formatter,
"serde error: {}", err,

View File

@ -127,7 +127,7 @@ executable_instruction!(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::ByteArray,
received_type: (&value).into(),
received_value: value,
},
)),

View File

@ -2,13 +2,12 @@ use crate::{
errors::{InstructionError, InstructionErrorKind},
interpreter::wasm::structures::{FunctionIndex, TypedIndex},
interpreter::Instruction,
types::InterfaceType,
};
executable_instruction!(
call_core(function_index: u32, instruction: Instruction) -> _ {
move |runtime| -> _ {
let instance = &mut runtime.wasm_instance;
let instance = &runtime.wasm_instance;
let index = FunctionIndex::new(function_index as usize);
let local_or_import = instance.local_or_import(index).ok_or_else(|| {
@ -29,21 +28,8 @@ executable_instruction!(
},
)
})?;
let input_types = inputs
.iter()
.map(Into::into)
.collect::<Vec<InterfaceType>>();
if input_types != local_or_import.inputs() {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportSignatureMismatch {
function_index,
expected: (local_or_import.inputs().to_vec(), vec![]),
received: (input_types, vec![]),
},
));
}
super::check_function_signature(&**instance, local_or_import, &inputs, instruction)?;
let outputs = local_or_import.call(&inputs).map_err(|_| {
InstructionError::new(

View File

@ -7,6 +7,8 @@ mod records;
mod strings;
mod swap2;
use crate::interpreter::wasm;
use crate::types::InterfaceType;
use crate::{
errors::{InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError},
values::{InterfaceValue, NativeType},
@ -153,6 +155,7 @@ pub enum Instruction {
/// The `string.size` instruction.
ByteArraySize,
/*
/// The `record.lift` instruction.
RecordLift {
/// The type index of the record.
@ -165,6 +168,8 @@ pub enum Instruction {
type_index: u32,
},
*/
/// The `record.lift_memory` instruction.
RecordLiftMemory {
/// The type index of the record.
@ -197,6 +202,114 @@ where
.map_err(|error| InstructionError::new(instruction, InstructionErrorKind::ToNative(error)))
}
pub(crate) fn check_function_signature<
'instance,
Instance,
Export,
LocalImport,
Memory,
MemoryView,
>(
instance: &'instance Instance,
local_import: &LocalImport,
values: &[InterfaceValue],
instruction: Instruction,
) -> Result<(), InstructionError>
where
Export: wasm::structures::Export + 'instance,
LocalImport: wasm::structures::LocalImport + 'instance,
Memory: wasm::structures::Memory<MemoryView> + 'instance,
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
let func_inputs = local_import.inputs();
for (func_input_arg, value) in func_inputs.iter().zip(values.iter()) {
is_value_compatible_to_type(instance, &func_input_arg, value, instruction)?;
}
Ok(())
}
/// Check whether the provided value could be a value of the provided type.
pub(crate) fn is_value_compatible_to_type<
'instance,
Instance,
Export,
LocalImport,
Memory,
MemoryView,
>(
instance: &'instance Instance,
interface_type: &InterfaceType,
interface_value: &InterfaceValue,
instruction: Instruction,
) -> Result<(), InstructionError>
where
Export: wasm::structures::Export + 'instance,
LocalImport: wasm::structures::LocalImport + 'instance,
Memory: wasm::structures::Memory<MemoryView> + 'instance,
MemoryView: wasm::structures::MemoryView,
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
{
match (&interface_type, interface_value) {
(InterfaceType::S8, InterfaceValue::S8(_)) => Ok(()),
(InterfaceType::S16, InterfaceValue::S16(_)) => Ok(()),
(InterfaceType::S32, InterfaceValue::S32(_)) => Ok(()),
(InterfaceType::S64, InterfaceValue::S64(_)) => Ok(()),
(InterfaceType::U8, InterfaceValue::U8(_)) => Ok(()),
(InterfaceType::U16, InterfaceValue::U16(_)) => Ok(()),
(InterfaceType::U32, InterfaceValue::U32(_)) => Ok(()),
(InterfaceType::U64, InterfaceValue::U64(_)) => Ok(()),
(InterfaceType::I32, InterfaceValue::I32(_)) => Ok(()),
(InterfaceType::I64, InterfaceValue::I64(_)) => Ok(()),
(InterfaceType::F32, InterfaceValue::F32(_)) => Ok(()),
(InterfaceType::F64, InterfaceValue::F64(_)) => Ok(()),
(InterfaceType::String, InterfaceValue::String(_)) => Ok(()),
(InterfaceType::ByteArray, InterfaceValue::ByteArray(_)) => Ok(()),
(InterfaceType::Record(ref record_name), InterfaceValue::Record(record_fields)) => {
let record_type = instance.wit_record_by_name(record_name).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::RecordTypeByNameIsMissing {
type_name: record_name.to_owned(),
},
)
})?;
if record_fields.len() != record_type.fields.len() {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: interface_type.clone(),
received_value: interface_value.clone(),
},
));
}
for (record_type_field, record_value_field) in
record_type.fields.iter().zip(record_fields.iter())
{
is_value_compatible_to_type(
instance,
&record_type_field.ty,
record_value_field,
instruction,
)?;
}
Ok(())
}
_ => Err(InstructionError::new(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: interface_type.clone(),
received_value: interface_value.clone(),
},
)),
}
}
#[cfg(test)]
pub(crate) mod tests {
use crate::{ast::*, interpreter::wasm, types::*, values::*};
@ -381,7 +494,7 @@ pub(crate) mod tests {
Some(&self.memory)
}
fn wit_type(&self, index: u32) -> Option<&Type> {
fn wit_type_by_id(&self, index: u32) -> Option<&Type> {
self.wit_types.get(index as usize)
}
}

View File

@ -33,7 +33,7 @@ macro_rules! lowering_lifting {
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::$from_variant,
received_type: (&wrong_value).into(),
received_value: wrong_value,
}
))
},

View File

@ -9,18 +9,16 @@ use crate::interpreter::instructions::to_native;
use crate::{
ast::{Type, TypeKind},
errors::{InstructionError, InstructionErrorKind},
interpreter::{
stack::{Stack, Stackable},
Instruction,
},
interpreter::Instruction,
types::{InterfaceType, RecordType},
values::{FlattenInterfaceValueIterator, InterfaceValue},
values::InterfaceValue,
vec1::Vec1,
};
use std::collections::VecDeque;
use std::convert::TryInto;
/*
/// Build an `InterfaceValue::Record` based on values on the stack.
///
/// To fill a record, every field `field_1` to `field_n` must get its
@ -105,10 +103,11 @@ where
}
})
}
*/
fn record_lift_memory_<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance mut Instance,
record_type: RecordType,
instance: &'instance Instance,
record_type: &RecordType,
offset: usize,
instruction: Instruction,
) -> Result<InterfaceValue, InstructionError>
@ -123,8 +122,8 @@ where
fn record_size(record_type: &RecordType) -> usize {
let mut record_size = 0;
for ty in record_type.fields.iter() {
let params_count = match ty {
for field_type in record_type.fields.iter() {
let params_count = match field_type.ty {
InterfaceType::String | InterfaceType::ByteArray => 2,
_ => 1,
};
@ -137,16 +136,16 @@ where
let length = record_type.fields.len();
let mut values = VecDeque::with_capacity(length);
let size = record_size(&record_type);
let size = record_size(record_type);
let data = read_from_instance_mem(instance, instruction, offset, size)?;
// TODO: add error handling
let data =
safe_transmute::transmute_many::<u64, safe_transmute::SingleManyGuard>(&data).unwrap();
let mut field_id = 0;
for field in record_type.fields.into_vec() {
for field in (*record_type.fields).iter() {
let value = data[field_id];
match field {
match &field.ty {
InterfaceType::S8 => {
values.push_back(InterfaceValue::S8(value as _));
}
@ -201,7 +200,7 @@ where
utils::deallocate(instance, instruction, string_offset as _, string_size as _)?;
} else {
values.push_back(InterfaceValue::String("".to_string()));
values.push_back(InterfaceValue::String(String::new()));
}
}
InterfaceType::ByteArray => {
@ -224,9 +223,21 @@ where
values.push_back(InterfaceValue::ByteArray(vec![]));
}
}
InterfaceType::Record(record_type) => {
InterfaceType::Record(record_type_name) => {
let offset = value;
let record_type =
instance
.wit_record_by_name(&record_type_name)
.ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::RecordTypeByNameIsMissing {
type_name: record_type_name.to_owned(),
},
)
})?;
values.push_back(record_lift_memory_(
instance,
record_type,
@ -275,8 +286,8 @@ where
.map_err(|k| InstructionError::new(instruction, k))?;
// TODO: size = 0
let instance = &mut runtime.wasm_instance;
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
let instance = &runtime.wasm_instance;
let record_type = match instance.wit_type_by_id(type_index).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::TypeIsMissing { type_index },
@ -294,7 +305,7 @@ where
}
};
let record = record_lift_memory_(*instance, record_type, offset, instruction)?;
let record = record_lift_memory_(&**instance, &record_type, offset, instruction)?;
runtime.stack.push(record);
Ok(())
@ -353,8 +364,8 @@ where
result.push(value.len() as _);
}
InterfaceValue::Record(record) => {
let record_ptr = record_lower_memory_(instance, instruction, record)?;
InterfaceValue::Record(values) => {
let record_ptr = record_lower_memory_(instance, instruction, values)?;
result.push(record_ptr as _);
}
@ -384,7 +395,7 @@ where
Box::new({
move |runtime| -> _ {
let instance = &mut runtime.wasm_instance;
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
let record_type = match instance.wit_type_by_id(type_index).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::TypeIsMissing { type_index },
@ -401,10 +412,9 @@ where
))
}
};
match runtime.stack.pop1() {
Some(InterfaceValue::Record(record_values))
if record_type == &(&*record_values).into() =>
{
Some(InterfaceValue::Record(record_values)) => {
/*
let value: Vec<u8> = crate::serde::de::from_interface_values(&record_values)
.map_err(|e| {
@ -426,8 +436,8 @@ where
Some(value) => Err(InstructionError::new(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::Record(record_type.clone()),
received_type: (&value).into(),
expected_type: InterfaceType::Record(record_type.name.clone()),
received_value: value,
},
)),
None => Err(InstructionError::new(
@ -439,6 +449,7 @@ where
})
}
/*
pub(crate) fn record_lower<Instance, Export, LocalImport, Memory, MemoryView>(
type_index: u32,
instruction: Instruction,
@ -498,3 +509,4 @@ where
}
})
}
*/

View File

@ -42,7 +42,7 @@ where
}
pub(super) fn write_to_instance_mem<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance mut Instance,
instance: &'instance Instance,
instruction: Instruction,
bytes: &[u8],
) -> Result<i32, InstructionError>
@ -74,7 +74,7 @@ where
}
pub(super) fn allocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance mut Instance,
instance: &'instance Instance,
instruction: Instruction,
size: i32,
) -> Result<i32, InstructionError>
@ -105,7 +105,7 @@ where
}
pub(super) fn deallocate<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance mut Instance,
instance: &'instance Instance,
instruction: Instruction,
mem_ptr: i32,
size: i32,
@ -128,7 +128,7 @@ where
}
fn call_core<'instance, Instance, Export, LocalImport, Memory, MemoryView>(
instance: &'instance mut Instance,
instance: &'instance Instance,
function_index: u32,
instruction: Instruction,
inputs: Vec<InterfaceValue>,
@ -147,20 +147,9 @@ where
InstructionErrorKind::LocalOrImportIsMissing { function_index },
)
})?;
let input_types = inputs
.iter()
.map(Into::into)
.collect::<Vec<InterfaceType>>();
if input_types != local_or_import.inputs() {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::LocalOrImportSignatureMismatch {
function_index,
expected: (local_or_import.inputs().to_vec(), vec![]),
received: (input_types, vec![]),
},
));
}
crate::interpreter::instructions::check_function_signature(instance, local_or_import, &inputs, instruction)?;
let outputs = local_or_import.call(&inputs).map_err(|_| {
InstructionError::new(
instruction,

View File

@ -131,7 +131,7 @@ executable_instruction!(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::String,
received_type: (&value).into(),
received_value: (&value).clone(),
},
)),

View File

@ -245,13 +245,14 @@ where
}
Instruction::ByteArraySize => instructions::byte_array_size(*instruction),
/*
Instruction::RecordLift { type_index } => {
instructions::record_lift(*type_index, *instruction)
}
Instruction::RecordLower { type_index } => {
instructions::record_lower(*type_index, *instruction)
}
*/
Instruction::RecordLiftMemory { type_index } => {
instructions::record_lift_memory(*type_index, *instruction)
}

View File

@ -1,5 +1,6 @@
#![allow(missing_docs)]
use crate::types::RecordType;
use crate::{ast, types::InterfaceType, values::InterfaceValue};
use std::{cell::Cell, ops::Deref};
@ -72,9 +73,10 @@ where
MV: MemoryView,
{
fn export(&self, export_name: &str) -> Option<&E>;
fn local_or_import<I: TypedIndex + LocalImportIndex>(&mut self, index: I) -> Option<&LI>;
fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, index: I) -> Option<&LI>;
fn memory(&self, index: usize) -> Option<&M>;
fn wit_type(&self, index: u32) -> Option<&ast::Type>;
fn wit_type_by_id(&self, index: u32) -> Option<&ast::Type>;
fn wit_record_by_name(&self, name: &str) -> Option<&RecordType>;
}
impl Export for () {
@ -154,11 +156,15 @@ where
None
}
fn local_or_import<I: TypedIndex + LocalImportIndex>(&mut self, _index: I) -> Option<&LI> {
fn local_or_import<I: TypedIndex + LocalImportIndex>(&self, _index: I) -> Option<&LI> {
None
}
fn wit_type(&self, _index: u32) -> Option<&ast::Type> {
fn wit_type_by_id(&self, _index: u32) -> Option<&ast::Type> {
None
}
fn wit_record_by_name(&self, _name: &str) -> Option<&RecordType> {
None
}
}

View File

@ -91,7 +91,7 @@ macro_rules! next {
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
expected_type: InterfaceType::$variant,
received_type: (*wrong_value).into(),
received_value: (*wrong_value).clone(),
}),
None => Err(DeserializeError::InputEmpty),
@ -122,7 +122,7 @@ impl<'de> Deserializer<'de> {
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
expected_type: InterfaceType::String,
received_type: (*wrong_value).into(),
received_value: (*wrong_value).clone(),
}),
None => Err(DeserializeError::InputEmpty),
@ -139,7 +139,7 @@ impl<'de> Deserializer<'de> {
Some(wrong_value) => Err(DeserializeError::TypeMismatch {
expected_type: InterfaceType::ByteArray,
received_type: (*wrong_value).into(),
received_value: (*wrong_value).clone(),
}),
None => Err(DeserializeError::InputEmpty),
@ -165,7 +165,7 @@ pub enum DeserializeError {
expected_type: InterfaceType,
/// The received type.
received_type: InterfaceType,
received_value: InterfaceValue,
},
/// Arbitrary message.
@ -186,11 +186,11 @@ impl Display for DeserializeError {
Self::InputEmpty => write!(formatter, "Unexpected end of input"),
Self::TypeMismatch {
ref expected_type,
ref received_type,
ref received_value,
} => write!(
formatter,
"Type mismatch detected, expected `{:?}` but received `{:?}`",
expected_type, received_type
"Type mismatch detected: `{:?}` can't be converted to `{:?}`",
received_value, expected_type,
),
}
}
@ -220,7 +220,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
Some(InterfaceValue::ByteArray(_)) => self.deserialize_bytes(visitor),
Some(InterfaceValue::I32(_)) => self.deserialize_i32(visitor),
Some(InterfaceValue::I64(_)) => self.deserialize_i64(visitor),
Some(InterfaceValue::Record(_)) => unreachable!("Records should have been flattened."), // already flattened
Some(InterfaceValue::Record(..)) => unreachable!("Records should have been flattened."), // already flattened
None => Err(DeserializeError::InputEmpty),
}
}

View File

@ -51,15 +51,30 @@ pub enum InterfaceType {
/// A 64-bits integer (as defiend in WebAssembly core).
I64,
/// A record.
Record(RecordType),
/// A record contains type name.
// TODO: consider making it &str
Record(String),
}
/// Represents a record field type.
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct RecordFieldType {
// TODO: make name optional to support structures with anonymous fields in Rust
/// A field name.
pub name: String,
/// A field type.
pub ty: InterfaceType,
}
/// Represents a record type.
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct RecordType {
/// Types representing the fields.
/// A record name.
pub name: String,
/// Types and names representing the fields.
/// A record must have at least one field, hence the
/// [`Vec1`][crate::vec1::Vec1].
pub fields: Vec1<InterfaceType>,
pub fields: Vec1<RecordFieldType>,
}

View File

@ -1,10 +1,6 @@
//! Defines WIT values and associated operations.
use crate::{
errors::WasmValueNativeCastError,
types::{InterfaceType, RecordType},
vec1::Vec1,
};
use crate::{errors::WasmValueNativeCastError, types::InterfaceType, vec1::Vec1};
use std::{convert::TryFrom, slice::Iter};
#[cfg(feature = "serde")]
@ -60,6 +56,7 @@ pub enum InterfaceValue {
Record(Vec1<InterfaceValue>),
}
/*
impl From<&InterfaceValue> for InterfaceType {
fn from(value: &InterfaceValue) -> Self {
match value {
@ -78,10 +75,11 @@ impl From<&InterfaceValue> for InterfaceType {
//InterfaceValue::Anyref(_) => Self::Anyref,
InterfaceValue::I32(_) => Self::I32,
InterfaceValue::I64(_) => Self::I64,
InterfaceValue::Record(values) => Self::Record((&**values).into()),
InterfaceValue::Record(name) => Self::Record(name.to_owned()),
}
}
}
*/
impl Default for InterfaceValue {
fn default() -> Self {
@ -89,6 +87,7 @@ impl Default for InterfaceValue {
}
}
/*
impl From<&Vec<InterfaceValue>> for RecordType {
fn from(values: &Vec<InterfaceValue>) -> Self {
RecordType {
@ -97,6 +96,7 @@ impl From<&Vec<InterfaceValue>> for RecordType {
}
}
}
*/
/// Represents a native type supported by WIT.
pub trait NativeType {
@ -123,7 +123,7 @@ macro_rules! native {
match w {
InterfaceValue::$variant(n) => Ok(n.clone()),
_ => Err(WasmValueNativeCastError {
from: w.into(),
from: w.clone(),
to: <$native_type>::INTERFACE_TYPE,
}),
}
@ -173,8 +173,8 @@ impl<'a> Iterator for FlattenInterfaceValueIterator<'a> {
}
// Recursively iterate over the record.
Some(InterfaceValue::Record(values)) => {
self.iterators.push(values.iter());
Some(InterfaceValue::Record(fields)) => {
self.iterators.push(fields.iter());
self.next()
}