Merge pull request #3 from fluencelabs/record_refactoring

Refactor Record and Function IT types
This commit is contained in:
vms 2020-09-16 00:23:58 +03:00 committed by GitHub
commit 05c2d9ddda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 574 additions and 323 deletions

12
Cargo.lock generated
View File

@ -47,6 +47,15 @@ dependencies = [
"static_assertions",
]
[[package]]
name = "log"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.3.3"
@ -186,8 +195,9 @@ checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
[[package]]
name = "wasmer-interface-types-fl"
version = "0.17.2"
version = "0.17.5"
dependencies = [
"log",
"nom",
"safe-transmute",
"serde",

View File

@ -1,6 +1,6 @@
[package]
name = "wasmer-interface-types-fl"
version = "0.17.2"
version = "0.17.5"
description = "WebAssembly Interface Types library for Wasmer"
license = "MIT"
authors = ["The Wasmer Engineering Team <engineering@wasmer.io>"]
@ -17,6 +17,7 @@ wast = "8.0"
serde = { version = "1.0", features = ["derive"], optional = true }
serde_json = "1.0"
safe-transmute = "0.11.0"
log = "0.4.11"
[features]
default = ["serde"]

View File

@ -17,6 +17,16 @@ pub enum TypeKind {
Record,
}
/// Represents the function argument type.
#[derive(PartialEq, Debug, Clone)]
pub struct FunctionArg {
/// A function argument name.
pub name: String,
/// A function argument type.
pub ty: InterfaceType,
}
/// Represents a type.
#[derive(PartialEq, Debug, Clone)]
pub enum Type {
@ -26,15 +36,8 @@ pub enum Type {
/// (@interface type (func (param i32 i32) (result string)))
/// ```
Function {
/// Name of a function.
name: String,
/// Types for the parameters (`(param …)`).
arg_types: Vec<InterfaceType>,
/// Name of function argument types.
// TODO: introduce a struct combines name and type of a field
arg_names: Vec<String>,
/// Types for the parameters (`(param (name i32))`).
arguments: Vec<FunctionArg>,
/// Types for the results (`(result …)`).
output_types: Vec<InterfaceType>,

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,32 @@ 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) = owned_string(input)?);
consume!((input, ty) = ty(input)?);
Ok((input, RecordFieldType { name, ty }))
}
fn function_arg<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], FunctionArg, E> {
if input.is_empty() {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}
consume!((input, name) = owned_string(input)?);
consume!((input, ty) = ty(input)?);
Ok((input, FunctionArg { name, ty }))
}
/// Parse an interface type.
fn ty<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
@ -97,9 +123,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_id) = uleb(input)?);
InterfaceType::Record(record_type)
InterfaceType::Record(record_id)
}
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
};
@ -111,11 +137,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) = owned_string(input)?;
let (output, fields) = list(output, record_field)?;
Ok((
output,
RecordType {
name,
fields: Vec1::new(fields).expect("Record must have at least one field, zero given."),
},
))
@ -262,34 +292,35 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
0x38 => (input, Instruction::ByteArrayLowerMemory),
0x39 => (input, Instruction::ByteArraySize),
0x25 => {
consume!((input, argument_0) = uleb(input)?);
/*
0x25 => {
consume!((input, argument_0) = uleb(input)?);
(
input,
Instruction::RecordLift {
type_index: argument_0 as u32,
},
)
}
0x26 => {
consume!((input, argument_0) = uleb(input)?);
(
input,
Instruction::RecordLower {
type_index: argument_0 as u32,
},
)
}
(
input,
Instruction::RecordLift {
type_index: argument_0 as u32,
},
)
}
0x26 => {
consume!((input, argument_0) = uleb(input)?);
(
input,
Instruction::RecordLower {
type_index: argument_0 as u32,
},
)
}
*/
0x3A => {
consume!((input, argument_0) = uleb(input)?);
(
input,
Instruction::RecordLiftMemory {
type_index: argument_0 as u32,
record_type_id: argument_0 as u32,
},
)
}
@ -299,7 +330,7 @@ fn instruction<'input, E: ParseError<&'input [u8]>>(
(
input,
Instruction::RecordLowerMemory {
type_index: argument_0 as u32,
record_type_id: argument_0 as u32,
},
)
}
@ -328,15 +359,11 @@ fn types<'input, E: ParseError<&'input [u8]>>(
match type_kind {
TypeKind::Function => {
consume!((input, name) = string(input)?);
consume!((input, arg_types) = list(input, ty)?);
consume!((input, arg_names) = list(input, owned_string)?);
consume!((input, arguments) = list(input, function_arg)?);
consume!((input, output_types) = list(input, ty)?);
types.push(Type::Function {
name: String::from(name),
arg_types,
arg_names,
arguments,
output_types,
});
}
@ -861,8 +888,11 @@ mod tests {
Instruction::StringLiftMemory,
Instruction::StringLowerMemory,
Instruction::StringSize,
/*
Instruction::RecordLift { type_index: 1 },
Instruction::RecordLower { type_index: 1 },
*/
],
));

View File

@ -17,6 +17,10 @@ mod keyword {
custom_keyword!(record);
custom_keyword!(field);
// Special symbols
custom_keyword!(comma = ",");
custom_keyword!(colon = ":");
// New types.
custom_keyword!(s8);
custom_keyword!(s16);
@ -154,22 +158,31 @@ 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."),
})
}
}
#[allow(clippy::suspicious_else_formatting)]
impl<'a> Parse<'a> for Instruction {
#[allow(clippy::cognitive_complexity)]
fn parse(parser: Parser<'a>) -> Result<Self> {
@ -339,7 +352,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,17 +366,19 @@ 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 {
type_index: parser.parse()?,
record_type_id: parser.parse()?,
})
} else if lookahead.peek::<keyword::record_lower_memory>() {
parser.parse::<keyword::record_lower_memory>()?;
Ok(Instruction::RecordLowerMemory {
type_index: parser.parse()?,
record_type_id: parser.parse()?,
})
} else if lookahead.peek::<keyword::dup>() {
parser.parse::<keyword::dup>()?;
@ -403,7 +420,7 @@ impl Parse<'_> for AtInterface {
#[derive(PartialEq, Debug)]
enum FunctionType {
Header(String, Vec<String>, Vec<InterfaceType>),
Header(Vec<FunctionArg>),
Output(Vec<InterfaceType>),
}
@ -414,17 +431,34 @@ impl Parse<'_> for FunctionType {
if lookahead.peek::<keyword::param>() {
parser.parse::<keyword::param>()?;
let func_name = parser.parse()?;
let mut names = vec![];
let mut types = vec![];
let mut arguments = vec![];
while !parser.is_empty() {
names.push(parser.parse()?);
types.push(parser.parse()?);
let arg_name = parser.step(|cursor| {
cursor
.id()
.ok_or_else(|| cursor.error("expecting argument identifier"))
})?;
if !arg_name.ends_with(':') {
parser.step(|cursor| {
if let Some((":", rest)) = cursor.reserved() {
return Ok(("", rest));
}
Err(cursor.error("expected : between an argument and a type"))
})?;
}
let arg_type: InterfaceType = parser.parse()?;
arguments.push(FunctionArg {
name: arg_name.trim_end_matches(':').to_string(),
ty: arg_type,
});
}
Ok(FunctionType::Header(func_name, names, types))
Ok(FunctionType::Header(arguments))
} else if lookahead.peek::<keyword::result>() {
parser.parse::<keyword::result>()?;
@ -491,38 +525,22 @@ impl<'a> Parse<'a> for Type {
if lookahead.peek::<keyword::func>() {
parser.parse::<keyword::func>()?;
let mut arg_types = vec![];
let mut arg_names = vec![];
let mut arguments = vec![];
let mut output_types = vec![];
let mut name: Option<String> = None;
while !parser.is_empty() {
let function_type = parser.parse::<FunctionType>()?;
match function_type {
FunctionType::Header(func_name, mut names, mut types) => {
name = Some(func_name);
arg_names.append(&mut names);
arg_types.append(&mut types);
},
FunctionType::Header(mut func_arguments) => {
arguments.append(&mut func_arguments);
}
FunctionType::Output(mut outputs) => output_types.append(&mut outputs),
}
}
if name.is_none() {
return Err(parser.error("Malformed wast: function doesn't contain name"));
}
if arg_types.len() != arg_names.len() {
return Err(parser.error("Malformed wast: function argument types count should be equal to argument names count"));
}
// It's has been already checked for None.
let name = name.unwrap();
Ok(Type::Function {
name,
arg_types,
arg_names,
arguments,
output_types,
})
} else if lookahead.peek::<keyword::record>() {
@ -878,8 +896,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

@ -127,20 +127,32 @@ where
InterfaceType::Anyref => 0x0b_u8.to_bytes(writer),
InterfaceType::I32 => 0x0c_u8.to_bytes(writer),
InterfaceType::I64 => 0x0d_u8.to_bytes(writer),
InterfaceType::Record(record_type) => {
InterfaceType::Record(record_id) => {
0x0e_u8.to_bytes(writer)?;
record_type.to_bytes(writer)
record_id.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)
}
}
@ -174,6 +186,16 @@ where
}
}
impl<W> ToBytes<W> for FunctionArg
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
self.name.to_bytes(writer)?;
self.ty.to_bytes(writer)
}
}
/// Encode a `Type` into bytes.
///
/// Decoder is in `decoders::binary::types`.
@ -184,15 +206,11 @@ where
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
match self {
Type::Function {
name,
arg_types,
arg_names,
arguments,
output_types,
} => {
TypeKind::Function.to_bytes(writer)?;
name.to_bytes(writer)?;
arg_types.to_bytes(writer)?;
arg_names.to_bytes(writer)?;
arguments.to_bytes(writer)?;
output_types.to_bytes(writer)?;
}
@ -363,7 +381,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)?
@ -372,11 +390,16 @@ where
0x26_u8.to_bytes(writer)?;
(*type_index as u64).to_bytes(writer)?
}
Instruction::RecordLiftMemory { type_index } => {
*/
Instruction::RecordLiftMemory {
record_type_id: type_index,
} => {
0x3A_u8.to_bytes(writer)?;
(*type_index as u64).to_bytes(writer)?
}
Instruction::RecordLowerMemory { type_index } => {
Instruction::RecordLowerMemory {
record_type_id: type_index,
} => {
0x3B_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 {} {{\n{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,14 +147,16 @@ 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)
}
Instruction::RecordLowerMemory { type_index } => {
format!("record.lower_memory {}", type_index)
}
*/
Instruction::RecordLiftMemory {
record_type_id: type_index,
} => format!("record.lift_memory {}", type_index),
Instruction::RecordLowerMemory {
record_type_id: type_index,
} => format!("record.lower_memory {}", type_index),
Instruction::Dup => "dup".into(),
Instruction::Swap2 => "swap2".into(),
}
@ -158,17 +165,17 @@ impl ToString for &Instruction {
/// Encode a list of `InterfaceType` representing inputs into a
/// string.
fn encode_arguments(arg_types: &[InterfaceType], arg_names: &[String]) -> String {
fn encode_function_arguments(arguments: &[FunctionArg]) -> String {
// here we know that arg_names and arg_types have the same length
if arg_names.is_empty() {
if arguments.is_empty() {
String::from("")
} else {
format!(
"\n (param{})",
arg_names.iter().zip(arg_types.iter()).fold(
arguments.iter().fold(
String::new(),
|mut accumulator, (name, ty)| {
accumulator.push(' ');
|mut accumulator, FunctionArg { name, ty }| {
accumulator.push_str(" $");
accumulator.push_str(name);
accumulator.push_str(": ");
accumulator.push_str(&ty.to_string());
@ -203,14 +210,11 @@ impl<'input> ToString for &Type {
fn to_string(&self) -> String {
match self {
Type::Function {
name,
arg_types,
arg_names,
arguments,
output_types,
} => format!(
r#"(@interface type (func {name} {args}{output_types}))"#,
name = name,
args = encode_arguments(arg_types, arg_names),
r#"(@interface type (func {args} {output_types}))"#,
args = encode_function_arguments(arguments),
output_types = output_types_to_result(&output_types),
),
@ -279,14 +283,16 @@ impl<'input> ToString for &Interfaces<'input> {
fn to_string(&self) -> String {
let mut output = String::new();
let types = self
.types
.iter()
.fold(String::new(), |mut accumulator, ty| {
accumulator.push('\n');
accumulator.push_str(&ty.to_string());
accumulator
});
let types =
self.types
.iter()
.enumerate()
.fold(String::new(), |mut accumulator, (id, ty)| {
accumulator.push('\n');
accumulator.push_str(&ty.to_string());
accumulator.push_str(&format!(" ;; {}", id));
accumulator
});
let imports = self
.imports
@ -485,8 +491,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,15 @@ pub enum InstructionErrorKind {
type_index: u32,
},
/// The searched by name type doesn't exist.
RecordTypeByNameIsMissing {
/// The record type name.
record_type_id: u64,
},
/// Corrupted record's been popped from the stack.
CorruptedRecord(String),
/// Read a type that has an unexpected type.
InvalidTypeKind {
/// The expected kind.
@ -199,11 +209,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 +271,19 @@ impl Display for InstructionErrorKind {
"read a type of kind `{:?}`, but the kind `{:?}` was expected",
received_kind, expected_kind
),
Self::RecordTypeByNameIsMissing { record_type_id: type_name } => write!(
formatter,
"type with `{}` is missing in a Wasm binary",
type_name
),
Self::CorruptedRecord(err) => write!(
formatter,
"{}",
err
),
Self::SerdeError(err) => write!(
formatter,
"serde error: {}", err,

View File

@ -15,6 +15,8 @@ executable_instruction!(
));
}
log::trace!("arg.get: pushing {:?} on the stack", invocation_inputs[index as usize]);
runtime.stack.push(invocation_inputs[index as usize].clone());
Ok(())

View File

@ -59,6 +59,8 @@ executable_instruction!(
.map(Cell::get)
.collect();
log::trace!("bytearray.lift_memory: pushing {:?} on the stack", data);
runtime.stack.push(InterfaceValue::ByteArray(data));
Ok(())
@ -104,6 +106,8 @@ executable_instruction!(
memory_view[byte_array_pointer as usize + nth].set(*byte);
}
log::trace!("bytearray.lower_memory: pushing {}, {} on the stack", byte_array_pointer, byte_array_length);
runtime.stack.push(InterfaceValue::I32(byte_array_pointer as i32));
runtime.stack.push(InterfaceValue::I32(byte_array_length));
@ -127,7 +131,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,10 @@ 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)?;
log::trace!("call-core: calling {} with arguments: {:?}", function_index, inputs);
let outputs = local_or_import.call(&inputs).map_err(|_| {
InstructionError::new(
@ -54,7 +42,7 @@ executable_instruction!(
)
})?;
log::trace!("call-core: call to {} succeeded with result {:?}", function_index, outputs);
for output in outputs.into_iter() {
runtime.stack.push(output)

View File

@ -14,6 +14,7 @@ executable_instruction!(
})?;
let value = value.clone();
log::trace!("dup: duplication {:?} value on the stack", value);
runtime.stack.push(value);
Ok(())

View File

@ -7,6 +7,9 @@ mod records;
mod strings;
mod swap2;
use crate::interpreter::wasm;
use crate::types::InterfaceType;
use crate::vec1::Vec1;
use crate::{
errors::{InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError},
values::{InterfaceValue, NativeType},
@ -153,6 +156,7 @@ pub enum Instruction {
/// The `string.size` instruction.
ByteArraySize,
/*
/// The `record.lift` instruction.
RecordLift {
/// The type index of the record.
@ -165,16 +169,17 @@ pub enum Instruction {
type_index: u32,
},
*/
/// The `record.lift_memory` instruction.
RecordLiftMemory {
/// The type index of the record.
type_index: u32,
record_type_id: u32,
},
/// The `record.lower_memory` instruction.
RecordLowerMemory {
/// The type index of the record.
type_index: u32,
record_type_id: u32,
},
/// The `dup` instructions.
@ -197,6 +202,143 @@ 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.arguments();
for (func_input_arg, value) in func_inputs.iter().zip(values.iter()) {
is_value_compatible_to_type(instance, &func_input_arg.ty, 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_type_id), InterfaceValue::Record(record_fields)) => {
is_record_fields_compatible_to_type(
instance,
*record_type_id,
record_fields,
instruction,
)?;
Ok(())
}
_ => Err(InstructionError::new(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: interface_type.clone(),
received_value: interface_value.clone(),
},
)),
}
}
pub(crate) fn is_record_fields_compatible_to_type<
'instance,
Instance,
Export,
LocalImport,
Memory,
MemoryView,
>(
instance: &'instance Instance,
record_type_id: u64,
record_fields: &[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 record_type = instance.wit_record_by_id(record_type_id).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id },
)
})?;
if record_fields.len() != record_type.fields.len() {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::Record(record_type_id),
// unwrap is safe here - len's been already checked
received_value: InterfaceValue::Record(Vec1::new(record_fields.to_vec()).unwrap()),
},
));
}
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(())
}
#[cfg(test)]
pub(crate) mod tests {
use crate::{ast::*, interpreter::wasm, types::*, values::*};
@ -217,7 +359,7 @@ pub(crate) mod tests {
self.outputs.len()
}
fn inputs(&self) -> &[InterfaceType] {
fn arguments(&self) -> &[InterfaceType] {
&self.inputs
}
@ -245,7 +387,7 @@ pub(crate) mod tests {
self.outputs.len()
}
fn inputs(&self) -> &[InterfaceType] {
fn arguments(&self) -> &[InterfaceType] {
&self.inputs
}
@ -353,12 +495,32 @@ pub(crate) mod tests {
},
memory: Memory::new(vec![Cell::new(0); 128]),
wit_types: vec![Type::Record(RecordType {
name: String::from("RecordType0"),
fields: vec1![
InterfaceType::I32,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::String, InterfaceType::F32],
}),
InterfaceType::I64,
RecordFieldType {
name: String::from("field_0"),
ty: InterfaceType::I32,
},
RecordFieldType {
name: String::from("field_1"),
ty: InterfaceType::Record(RecordType {
name: String::from("RecordType1"),
fields: vec1![
RecordFieldType {
name: String::from("field_0"),
ty: InterfaceType::String,
},
RecordFieldType {
name: String::from("field1"),
ty: InterfaceType::F32
}
],
}),
},
RecordFieldType {
name: String::from("field_2"),
ty: InterfaceType::I64,
}
],
})],
}
@ -381,8 +543,12 @@ 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)
}
fn wit_record_by_id(&self, index: u64) -> Option<&RecordType> {
self.wit_types.get(index as _)
}
}
}

View File

@ -15,25 +15,30 @@ macro_rules! lowering_lifting {
Some(InterfaceValue::$from_variant(value)) => {
runtime
.stack
.push(InterfaceValue::$to_variant(value.try_into().map_err(
|_| {
InstructionError::new(
instruction,
InstructionErrorKind::LoweringLifting {
from: InterfaceType::$from_variant,
to: InterfaceType::$to_variant
},
)
},
)?))
}
.push({
let converted_value = InterfaceValue::$to_variant(value.try_into().map_err(
|_| {
InstructionError::new(
instruction,
InstructionErrorKind::LoweringLifting {
from: InterfaceType::$from_variant,
to: InterfaceType::$to_variant
},
)
},
)?);
log::trace!("{}: converting {:?} to {:?}", $instruction_name, value, converted_value);
converted_value
})
}
Some(wrong_value) => {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::$from_variant,
received_type: (&wrong_value).into(),
received_value: wrong_value,
}
))
},

View File

@ -3,24 +3,19 @@ mod utils;
use utils::read_from_instance_mem;
use utils::write_to_instance_mem;
// use crate::interpreter::wasm;
use crate::interpreter::instructions::to_native;
use crate::interpreter::instructions::{is_record_fields_compatible_to_type, 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 +100,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 +119,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 +133,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 _));
}
@ -199,7 +195,7 @@ where
let string = String::from_utf8(string_mem).unwrap();
values.push_back(InterfaceValue::String(string));
} else {
values.push_back(InterfaceValue::String("".to_string()));
values.push_back(InterfaceValue::String(String::new()));
}
}
InterfaceType::ByteArray => {
@ -220,9 +216,18 @@ where
values.push_back(InterfaceValue::ByteArray(vec![]));
}
}
InterfaceType::Record(record_type) => {
InterfaceType::Record(record_type_id) => {
let offset = value;
let record_type = instance.wit_record_by_id(*record_type_id).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::RecordTypeByNameIsMissing {
record_type_id: *record_type_id,
},
)
})?;
values.push_back(record_lift_memory_(
instance,
record_type,
@ -243,7 +248,7 @@ where
}
pub(crate) fn record_lift_memory<Instance, Export, LocalImport, Memory, MemoryView>(
type_index: u32,
record_type_id: u64,
instruction: Instruction,
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
where
@ -271,26 +276,17 @@ 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 = instance.wit_record_by_id(record_type_id).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::TypeIsMissing { type_index },
InstructionErrorKind::RecordTypeByNameIsMissing { record_type_id },
)
})? {
Type::Record(record_type) => record_type.clone(),
Type::Function { .. } => {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::InvalidTypeKind {
expected_kind: TypeKind::Record,
received_kind: TypeKind::Function,
},
))
}
};
})?;
let record = record_lift_memory_(*instance, record_type, offset, instruction)?;
let record = record_lift_memory_(&**instance, record_type, offset, instruction)?;
log::trace!("record.lift_memory: pushing {:?} on the stack", record);
runtime.stack.push(record);
Ok(())
@ -349,9 +345,10 @@ 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)?;
log::trace!("record.lower_memory: pushing {:?} on the stack", record_ptr);
result.push(record_ptr as _);
}
}
@ -364,7 +361,7 @@ where
}
pub(crate) fn record_lower_memory<Instance, Export, LocalImport, Memory, MemoryView>(
type_index: u32,
record_type_id: u64,
instruction: Instruction,
) -> crate::interpreter::ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
where
@ -380,41 +377,16 @@ where
Box::new({
move |runtime| -> _ {
let instance = &mut runtime.wasm_instance;
let record_type = match instance.wit_type(type_index).ok_or_else(|| {
InstructionError::new(
instruction,
InstructionErrorKind::TypeIsMissing { type_index },
)
})? {
Type::Record(record_type) => record_type,
Type::Function { .. } => {
return Err(InstructionError::new(
instruction,
InstructionErrorKind::InvalidTypeKind {
expected_kind: TypeKind::Record,
received_kind: TypeKind::Function,
},
))
}
};
match runtime.stack.pop1() {
Some(InterfaceValue::Record(record_values))
if record_type == &(&*record_values).into() =>
{
/*
let value: Vec<u8> = crate::serde::de::from_interface_values(&record_values)
.map_err(|e| {
InstructionError::new(
instruction,
InstructionErrorKind::SerdeError(e.to_string()),
)
})?;
let value_pointer = write_to_instance_mem(*instance, instruction, &value)?;
runtime.stack.push(InterfaceValue::I32(value_pointer));
runtime.stack.push(InterfaceValue::I32(value.len() as _));
*/
let offset = record_lower_memory_(*instance, instruction, record_values)?;
match runtime.stack.pop1() {
Some(InterfaceValue::Record(record_fields)) => {
is_record_fields_compatible_to_type(
&**instance,
record_type_id,
&record_fields,
instruction,
)?;
let offset = record_lower_memory_(*instance, instruction, record_fields)?;
runtime.stack.push(InterfaceValue::I32(offset));
Ok(())
@ -422,8 +394,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_id),
received_value: value,
},
)),
None => Err(InstructionError::new(
@ -435,6 +407,7 @@ where
})
}
/*
pub(crate) fn record_lower<Instance, Export, LocalImport, Memory, MemoryView>(
type_index: u32,
instruction: Instruction,
@ -494,3 +467,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,14 @@ 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

@ -62,6 +62,7 @@ executable_instruction!(
let string = String::from_utf8(data)
.map_err(|error| InstructionError::new(instruction, InstructionErrorKind::String(error)))?;
log::trace!("string.lift_memory: pushing {:?} on the stack", string);
runtime.stack.push(InterfaceValue::String(string));
Ok(())
@ -108,6 +109,7 @@ executable_instruction!(
memory_view[string_pointer as usize + nth].set(*byte);
}
log::trace!("string.lower_memory: pushing {}, {} on the stack", string_pointer, string_length);
runtime.stack.push(InterfaceValue::I32(string_pointer as i32));
runtime.stack.push(InterfaceValue::I32(string_length));
@ -122,6 +124,8 @@ executable_instruction!(
match runtime.stack.pop1() {
Some(InterfaceValue::String(string)) => {
let length = string.len() as i32;
log::trace!("string.size: pushing {} on the stack", length);
runtime.stack.push(InterfaceValue::I32(length));
Ok(())
@ -131,7 +135,7 @@ executable_instruction!(
instruction,
InstructionErrorKind::InvalidValueOnTheStack {
expected_type: InterfaceType::String,
received_type: (&value).into(),
received_value: (&value).clone(),
},
)),

View File

@ -13,6 +13,7 @@ executable_instruction!(
)
})?;
log::trace!("swap2: swapping {:?}, {:?} values on the stack", values[0], values[1]);
runtime.stack.push(values.remove(1));
runtime.stack.push(values.remove(0));

View File

@ -245,18 +245,19 @@ 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)
*/
Instruction::RecordLiftMemory { record_type_id } => {
instructions::record_lift_memory(*record_type_id as _, *instruction)
}
Instruction::RecordLowerMemory { type_index } => {
instructions::record_lower_memory(*type_index, *instruction)
Instruction::RecordLowerMemory { record_type_id } => {
instructions::record_lower_memory(*record_type_id as _, *instruction)
}
Instruction::Dup => instructions::dup(*instruction),
Instruction::Swap2 => instructions::swap2(*instruction),

View File

@ -1,6 +1,8 @@
#![allow(missing_docs)]
use crate::{ast, types::InterfaceType, values::InterfaceValue};
use crate::ast::FunctionArg;
use crate::types::RecordType;
use crate::{types::InterfaceType, values::InterfaceValue};
use std::{cell::Cell, ops::Deref};
pub trait TypedIndex: Copy + Clone {
@ -42,7 +44,7 @@ impl LocalImportIndex for FunctionIndex {
pub trait Export {
fn inputs_cardinality(&self) -> usize;
fn outputs_cardinality(&self) -> usize;
fn inputs(&self) -> &[InterfaceType];
fn arguments(&self) -> &[FunctionArg];
fn outputs(&self) -> &[InterfaceType];
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()>;
}
@ -50,7 +52,7 @@ pub trait Export {
pub trait LocalImport {
fn inputs_cardinality(&self) -> usize;
fn outputs_cardinality(&self) -> usize;
fn inputs(&self) -> &[InterfaceType];
fn arguments(&self) -> &[FunctionArg];
fn outputs(&self) -> &[InterfaceType];
fn call(&self, arguments: &[InterfaceValue]) -> Result<Vec<InterfaceValue>, ()>;
}
@ -72,9 +74,9 @@ 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_record_by_id(&self, index: u64) -> Option<&RecordType>;
}
impl Export for () {
@ -86,7 +88,7 @@ impl Export for () {
0
}
fn inputs(&self) -> &[InterfaceType] {
fn arguments(&self) -> &[FunctionArg] {
&[]
}
@ -108,7 +110,7 @@ impl LocalImport for () {
0
}
fn inputs(&self) -> &[InterfaceType] {
fn arguments(&self) -> &[FunctionArg] {
&[]
}
@ -154,11 +156,11 @@ 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_record_by_id(&self, _index: u64) -> 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

@ -4,7 +4,7 @@ use crate::vec1::Vec1;
use serde::{Deserialize, Serialize};
/// Represents the types supported by WIT.
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[derive(PartialEq, Eq, Debug, Clone, Hash, Serialize, Deserialize)]
pub enum InterfaceType {
/// A 8-bits signed integer.
S8,
@ -51,15 +51,42 @@ pub enum InterfaceType {
/// A 64-bits integer (as defiend in WebAssembly core).
I64,
/// A record.
Record(RecordType),
/// A record contains record index from interfaces AST.
Record(u64),
}
/// Represents a record field type.
#[derive(PartialEq, Eq, Debug, Clone, Hash, 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)]
#[derive(PartialEq, Eq, Debug, Clone, Hash, 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>,
}
impl Default for RecordType {
fn default() -> Self {
Self {
name: String::new(),
fields: Vec1::new(vec![RecordFieldType {
name: String::new(),
ty: InterfaceType::S8,
}])
.unwrap(),
}
}
}

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,44 +56,12 @@ pub enum InterfaceValue {
Record(Vec1<InterfaceValue>),
}
impl From<&InterfaceValue> for InterfaceType {
fn from(value: &InterfaceValue) -> Self {
match value {
InterfaceValue::S8(_) => Self::S8,
InterfaceValue::S16(_) => Self::S16,
InterfaceValue::S32(_) => Self::S32,
InterfaceValue::S64(_) => Self::S64,
InterfaceValue::U8(_) => Self::U8,
InterfaceValue::U16(_) => Self::U16,
InterfaceValue::U32(_) => Self::U32,
InterfaceValue::U64(_) => Self::U64,
InterfaceValue::F32(_) => Self::F32,
InterfaceValue::F64(_) => Self::F64,
InterfaceValue::String(_) => Self::String,
InterfaceValue::ByteArray(_) => Self::ByteArray,
//InterfaceValue::Anyref(_) => Self::Anyref,
InterfaceValue::I32(_) => Self::I32,
InterfaceValue::I64(_) => Self::I64,
InterfaceValue::Record(values) => Self::Record((&**values).into()),
}
}
}
impl Default for InterfaceValue {
fn default() -> Self {
Self::I32(0)
}
}
impl From<&Vec<InterfaceValue>> for RecordType {
fn from(values: &Vec<InterfaceValue>) -> Self {
RecordType {
fields: Vec1::new(values.iter().map(Into::into).collect())
.expect("Record must have at least one field, zero given."),
}
}
}
/// Represents a native type supported by WIT.
pub trait NativeType {
/// The associated interface type that maps to the native type.
@ -123,7 +87,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 +137,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()
}

View File

@ -9,7 +9,7 @@ use std::{
/// `Vec1<T>` represents a non-empty `Vec<T>`. It derefs to `Vec<T>`
/// directly.
#[derive(Clone, PartialEq, Serialize, Deserialize, Default)]
#[derive(Clone, PartialEq, Eq, Serialize, Hash, Deserialize, Default)]
pub struct Vec1<T>(Vec<T>)
where
T: Debug;