mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-27 07:31:33 +00:00
feat(interface-types) Introduce RecordType
for InterfaceType
and Type
.
The `Type::Record` variant now is defined by `RecordType`. In addition, `InterfaceType` has a new variant: `Record`, that is also defined by `RecordType`. Encoders and decoders are updated to consider `RecordType`, which removes code duplication and simplify code.
This commit is contained in:
@ -48,6 +48,16 @@ pub enum InterfaceType {
|
|||||||
|
|
||||||
/// A 64-bits integer (as defiend in WebAssembly core).
|
/// A 64-bits integer (as defiend in WebAssembly core).
|
||||||
I64,
|
I64,
|
||||||
|
|
||||||
|
/// A record.
|
||||||
|
Record(RecordType),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Representing a record type.
|
||||||
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
pub struct RecordType {
|
||||||
|
/// Types representing the fields.
|
||||||
|
pub fields: Vec<InterfaceType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the kind of type.
|
/// Represents the kind of type.
|
||||||
@ -81,10 +91,7 @@ pub enum Type {
|
|||||||
/// ```wasm,ignore
|
/// ```wasm,ignore
|
||||||
/// (@interface type (record string i32))
|
/// (@interface type (record string i32))
|
||||||
/// ```
|
/// ```
|
||||||
Record {
|
Record(RecordType),
|
||||||
/// Types representing the fields.
|
|
||||||
fields: Vec<InterfaceType>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an imported function.
|
/// Represents an imported function.
|
||||||
|
@ -7,31 +7,6 @@ use nom::{
|
|||||||
};
|
};
|
||||||
use std::{convert::TryFrom, str};
|
use std::{convert::TryFrom, str};
|
||||||
|
|
||||||
/// Parse an `InterfaceType`.
|
|
||||||
impl TryFrom<u8> for InterfaceType {
|
|
||||||
type Error = &'static str;
|
|
||||||
|
|
||||||
fn try_from(code: u8) -> Result<Self, Self::Error> {
|
|
||||||
Ok(match code {
|
|
||||||
0 => Self::S8,
|
|
||||||
1 => Self::S16,
|
|
||||||
2 => Self::S32,
|
|
||||||
3 => Self::S64,
|
|
||||||
4 => Self::U8,
|
|
||||||
5 => Self::U16,
|
|
||||||
6 => Self::U32,
|
|
||||||
7 => Self::U64,
|
|
||||||
8 => Self::F32,
|
|
||||||
9 => Self::F64,
|
|
||||||
10 => Self::String,
|
|
||||||
11 => Self::Anyref,
|
|
||||||
12 => Self::I32,
|
|
||||||
13 => Self::I64,
|
|
||||||
_ => return Err("Unknown interface type code."),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a type kind.
|
/// Parse a type kind.
|
||||||
impl TryFrom<u8> for TypeKind {
|
impl TryFrom<u8> for TypeKind {
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
@ -95,6 +70,51 @@ fn uleb<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'i
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse an interface type.
|
||||||
|
fn ty<'input, E: ParseError<&'input [u8]>>(
|
||||||
|
mut input: &'input [u8],
|
||||||
|
) -> IResult<&'input [u8], InterfaceType, E> {
|
||||||
|
if input.is_empty() {
|
||||||
|
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
|
||||||
|
}
|
||||||
|
|
||||||
|
consume!((input, opcode) = byte(input)?);
|
||||||
|
|
||||||
|
let ty = match opcode {
|
||||||
|
0x00 => InterfaceType::S8,
|
||||||
|
0x01 => InterfaceType::S16,
|
||||||
|
0x02 => InterfaceType::S32,
|
||||||
|
0x03 => InterfaceType::S64,
|
||||||
|
0x04 => InterfaceType::U8,
|
||||||
|
0x05 => InterfaceType::U16,
|
||||||
|
0x06 => InterfaceType::U32,
|
||||||
|
0x07 => InterfaceType::U64,
|
||||||
|
0x08 => InterfaceType::F32,
|
||||||
|
0x09 => InterfaceType::F64,
|
||||||
|
0x0a => InterfaceType::String,
|
||||||
|
0x0b => InterfaceType::Anyref,
|
||||||
|
0x0c => InterfaceType::I32,
|
||||||
|
0x0d => InterfaceType::I64,
|
||||||
|
0x0e => {
|
||||||
|
consume!((input, record_type) = record_type(input)?);
|
||||||
|
|
||||||
|
InterfaceType::Record(record_type)
|
||||||
|
}
|
||||||
|
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((input, ty))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse an record type.
|
||||||
|
fn record_type<'input, E: ParseError<&'input [u8]>>(
|
||||||
|
input: &'input [u8],
|
||||||
|
) -> IResult<&'input [u8], RecordType, E> {
|
||||||
|
let (output, fields) = list(input, ty)?;
|
||||||
|
|
||||||
|
Ok((output, RecordType { fields }))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a UTF-8 string.
|
/// Parse a UTF-8 string.
|
||||||
fn string<'input, E: ParseError<&'input [u8]>>(
|
fn string<'input, E: ParseError<&'input [u8]>>(
|
||||||
input: &'input [u8],
|
input: &'input [u8],
|
||||||
@ -144,22 +164,6 @@ fn list<'input, I, E: ParseError<&'input [u8]>>(
|
|||||||
Ok((input, items))
|
Ok((input, items))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a type.
|
|
||||||
fn ty<'input, E: ParseError<&'input [u8]>>(
|
|
||||||
input: &'input [u8],
|
|
||||||
) -> IResult<&'input [u8], InterfaceType, E> {
|
|
||||||
if input.is_empty() {
|
|
||||||
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (output, ty) = byte(input)?;
|
|
||||||
|
|
||||||
match InterfaceType::try_from(ty) {
|
|
||||||
Ok(ty) => Ok((output, ty)),
|
|
||||||
Err(_) => Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse an instruction with its arguments.
|
/// Parse an instruction with its arguments.
|
||||||
fn instruction<'input, E: ParseError<&'input [u8]>>(
|
fn instruction<'input, E: ParseError<&'input [u8]>>(
|
||||||
input: &'input [u8],
|
input: &'input [u8],
|
||||||
@ -261,9 +265,9 @@ fn types<'input, E: ParseError<&'input [u8]>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
TypeKind::Record => {
|
TypeKind::Record => {
|
||||||
consume!((input, fields) = list(input, ty)?);
|
consume!((input, record_type) = record_type(input)?);
|
||||||
|
|
||||||
types.push(Type::Record { fields });
|
types.push(Type::Record(record_type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -575,6 +579,95 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ty() {
|
||||||
|
let input = &[
|
||||||
|
0x0f, // list of 15 items
|
||||||
|
0x00, // S8
|
||||||
|
0x01, // S16
|
||||||
|
0x02, // S32
|
||||||
|
0x03, // S64
|
||||||
|
0x04, // U8
|
||||||
|
0x05, // U16
|
||||||
|
0x06, // U32
|
||||||
|
0x07, // U64
|
||||||
|
0x08, // F32
|
||||||
|
0x09, // F64
|
||||||
|
0x0a, // String
|
||||||
|
0x0b, // Anyref
|
||||||
|
0x0c, // I32
|
||||||
|
0x0d, // I64
|
||||||
|
0x0e, 0x01, 0x02, // Record
|
||||||
|
0x01,
|
||||||
|
];
|
||||||
|
let output = Ok((
|
||||||
|
&[0x01][..],
|
||||||
|
vec![
|
||||||
|
InterfaceType::S8,
|
||||||
|
InterfaceType::S16,
|
||||||
|
InterfaceType::S32,
|
||||||
|
InterfaceType::S64,
|
||||||
|
InterfaceType::U8,
|
||||||
|
InterfaceType::U16,
|
||||||
|
InterfaceType::U32,
|
||||||
|
InterfaceType::U64,
|
||||||
|
InterfaceType::F32,
|
||||||
|
InterfaceType::F64,
|
||||||
|
InterfaceType::String,
|
||||||
|
InterfaceType::Anyref,
|
||||||
|
InterfaceType::I32,
|
||||||
|
InterfaceType::I64,
|
||||||
|
InterfaceType::Record(RecordType {
|
||||||
|
fields: vec![InterfaceType::S32],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(list::<_, ()>(input, ty), output);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_type() {
|
||||||
|
let input = &[
|
||||||
|
0x03, // list of 3 items
|
||||||
|
0x01, // 1 field
|
||||||
|
0x0a, // String
|
||||||
|
0x02, // 2 fields
|
||||||
|
0x0a, // String
|
||||||
|
0x0c, // I32
|
||||||
|
0x03, // 3 fields
|
||||||
|
0x0a, // String
|
||||||
|
0x0e, // Record
|
||||||
|
0x02, // 2 fields
|
||||||
|
0x0c, // I32
|
||||||
|
0x0c, // I32
|
||||||
|
0x09, // F64
|
||||||
|
0x01,
|
||||||
|
];
|
||||||
|
let output = Ok((
|
||||||
|
&[0x01][..],
|
||||||
|
vec![
|
||||||
|
RecordType {
|
||||||
|
fields: vec![InterfaceType::String],
|
||||||
|
},
|
||||||
|
RecordType {
|
||||||
|
fields: vec![InterfaceType::String, InterfaceType::I32],
|
||||||
|
},
|
||||||
|
RecordType {
|
||||||
|
fields: vec![
|
||||||
|
InterfaceType::String,
|
||||||
|
InterfaceType::Record(RecordType {
|
||||||
|
fields: vec![InterfaceType::I32, InterfaceType::I32],
|
||||||
|
}),
|
||||||
|
InterfaceType::F64,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(list::<_, ()>(input, record_type), output);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_string() {
|
fn test_string() {
|
||||||
let input = &[
|
let input = &[
|
||||||
@ -602,50 +695,7 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let output = Ok((&[0x07][..], vec!["a", "bc"]));
|
let output = Ok((&[0x07][..], vec!["a", "bc"]));
|
||||||
|
|
||||||
assert_eq!(list::<&str, ()>(input, string), output);
|
assert_eq!(list::<_, ()>(input, string), output);
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ty() {
|
|
||||||
let input = &[
|
|
||||||
0x0e, // list of 14 items
|
|
||||||
0x00, // S8
|
|
||||||
0x01, // S16
|
|
||||||
0x02, // S32
|
|
||||||
0x03, // S64
|
|
||||||
0x04, // U8
|
|
||||||
0x05, // U16
|
|
||||||
0x06, // U32
|
|
||||||
0x07, // U64
|
|
||||||
0x08, // F32
|
|
||||||
0x09, // F64
|
|
||||||
0x0a, // String
|
|
||||||
0x0b, // Anyref
|
|
||||||
0x0c, // I32
|
|
||||||
0x0d, // I64
|
|
||||||
0x01,
|
|
||||||
];
|
|
||||||
let output = Ok((
|
|
||||||
&[0x01][..],
|
|
||||||
vec![
|
|
||||||
InterfaceType::S8,
|
|
||||||
InterfaceType::S16,
|
|
||||||
InterfaceType::S32,
|
|
||||||
InterfaceType::S64,
|
|
||||||
InterfaceType::U8,
|
|
||||||
InterfaceType::U16,
|
|
||||||
InterfaceType::U32,
|
|
||||||
InterfaceType::U64,
|
|
||||||
InterfaceType::F32,
|
|
||||||
InterfaceType::F64,
|
|
||||||
InterfaceType::String,
|
|
||||||
InterfaceType::Anyref,
|
|
||||||
InterfaceType::I32,
|
|
||||||
InterfaceType::I64,
|
|
||||||
],
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(list::<InterfaceType, ()>(input, ty), output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -734,7 +784,7 @@ mod tests {
|
|||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(list::<Instruction, ()>(input, instruction), output);
|
assert_eq!(list::<_, ()>(input, instruction), output);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -787,9 +837,9 @@ mod tests {
|
|||||||
inputs: vec![InterfaceType::S32, InterfaceType::S32],
|
inputs: vec![InterfaceType::S32, InterfaceType::S32],
|
||||||
outputs: vec![InterfaceType::S32],
|
outputs: vec![InterfaceType::S32],
|
||||||
},
|
},
|
||||||
Type::Record {
|
Type::Record(RecordType {
|
||||||
fields: vec![InterfaceType::S32, InterfaceType::S32],
|
fields: vec![InterfaceType::S32, InterfaceType::S32],
|
||||||
},
|
}),
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ mod keyword {
|
|||||||
custom_keyword!(implement);
|
custom_keyword!(implement);
|
||||||
custom_keyword!(r#type = "type");
|
custom_keyword!(r#type = "type");
|
||||||
custom_keyword!(record);
|
custom_keyword!(record);
|
||||||
|
custom_keyword!(field);
|
||||||
|
|
||||||
// New types.
|
// New types.
|
||||||
custom_keyword!(s8);
|
custom_keyword!(s8);
|
||||||
@ -126,12 +127,32 @@ impl Parse<'_> for InterfaceType {
|
|||||||
parser.parse::<keyword::i64>()?;
|
parser.parse::<keyword::i64>()?;
|
||||||
|
|
||||||
Ok(InterfaceType::I64)
|
Ok(InterfaceType::I64)
|
||||||
|
} else if lookahead.peek::<keyword::record>() {
|
||||||
|
Ok(InterfaceType::Record(parser.parse()?))
|
||||||
} else {
|
} else {
|
||||||
Err(lookahead.error())
|
Err(lookahead.error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Parse<'_> for RecordType {
|
||||||
|
fn parse(parser: Parser<'_>) -> Result<Self> {
|
||||||
|
parser.parse::<keyword::record>()?;
|
||||||
|
|
||||||
|
let mut fields = vec![];
|
||||||
|
|
||||||
|
while !parser.is_empty() {
|
||||||
|
fields.push(parser.parens(|parser| {
|
||||||
|
parser.parse::<keyword::field>()?;
|
||||||
|
|
||||||
|
parser.parse()
|
||||||
|
})?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(RecordType { fields })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Parse<'a> for Instruction {
|
impl<'a> Parse<'a> for Instruction {
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
fn parse(parser: Parser<'a>) -> Result<Self> {
|
fn parse(parser: Parser<'a>) -> Result<Self> {
|
||||||
@ -425,15 +446,7 @@ impl<'a> Parse<'a> for Type {
|
|||||||
outputs: output_types,
|
outputs: output_types,
|
||||||
})
|
})
|
||||||
} else if lookahead.peek::<keyword::record>() {
|
} else if lookahead.peek::<keyword::record>() {
|
||||||
parser.parse::<keyword::record>()?;
|
Ok(Type::Record(parser.parse()?))
|
||||||
|
|
||||||
let mut fields = vec![];
|
|
||||||
|
|
||||||
while !parser.is_empty() {
|
|
||||||
fields.push(parser.parse()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Type::Record { fields })
|
|
||||||
} else {
|
} else {
|
||||||
Err(lookahead.error())
|
Err(lookahead.error())
|
||||||
}
|
}
|
||||||
@ -622,8 +635,21 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_interface_type() {
|
fn test_interface_type() {
|
||||||
let inputs = vec![
|
let inputs = vec![
|
||||||
"s8", "s16", "s32", "s64", "u8", "u16", "u32", "u64", "f32", "f64", "string", "anyref",
|
"s8",
|
||||||
"i32", "i64",
|
"s16",
|
||||||
|
"s32",
|
||||||
|
"s64",
|
||||||
|
"u8",
|
||||||
|
"u16",
|
||||||
|
"u32",
|
||||||
|
"u64",
|
||||||
|
"f32",
|
||||||
|
"f64",
|
||||||
|
"string",
|
||||||
|
"anyref",
|
||||||
|
"i32",
|
||||||
|
"i64",
|
||||||
|
"record (field string)",
|
||||||
];
|
];
|
||||||
let outputs = vec![
|
let outputs = vec![
|
||||||
InterfaceType::S8,
|
InterfaceType::S8,
|
||||||
@ -640,6 +666,9 @@ mod tests {
|
|||||||
InterfaceType::Anyref,
|
InterfaceType::Anyref,
|
||||||
InterfaceType::I32,
|
InterfaceType::I32,
|
||||||
InterfaceType::I64,
|
InterfaceType::I64,
|
||||||
|
InterfaceType::Record(RecordType {
|
||||||
|
fields: vec![InterfaceType::String],
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(inputs.len(), outputs.len());
|
assert_eq!(inputs.len(), outputs.len());
|
||||||
@ -652,6 +681,41 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_type() {
|
||||||
|
let inputs = vec![
|
||||||
|
"record (field string)",
|
||||||
|
"record (field string) (field i32)",
|
||||||
|
"record (field string) (field record (field i32) (field i32)) (field f64)",
|
||||||
|
];
|
||||||
|
let outputs = vec![
|
||||||
|
RecordType {
|
||||||
|
fields: vec![InterfaceType::String],
|
||||||
|
},
|
||||||
|
RecordType {
|
||||||
|
fields: vec![InterfaceType::String, InterfaceType::I32],
|
||||||
|
},
|
||||||
|
RecordType {
|
||||||
|
fields: vec![
|
||||||
|
InterfaceType::String,
|
||||||
|
InterfaceType::Record(RecordType {
|
||||||
|
fields: vec![InterfaceType::I32, InterfaceType::I32],
|
||||||
|
}),
|
||||||
|
InterfaceType::F64,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(inputs.len(), outputs.len());
|
||||||
|
|
||||||
|
for (input, output) in inputs.iter().zip(outputs.iter()) {
|
||||||
|
assert_eq!(
|
||||||
|
&parser::parse::<RecordType>(&buffer(input)).unwrap(),
|
||||||
|
output
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_instructions() {
|
fn test_instructions() {
|
||||||
let inputs = vec![
|
let inputs = vec![
|
||||||
@ -790,10 +854,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_type_record() {
|
fn test_type_record() {
|
||||||
let input = buffer(r#"(@interface type (record string i32))"#);
|
let input = buffer(r#"(@interface type (record (field string) (field i32)))"#);
|
||||||
let output = Interface::Type(Type::Record {
|
let output = Interface::Type(Type::Record(RecordType {
|
||||||
fields: vec![InterfaceType::String, InterfaceType::I32],
|
fields: vec![InterfaceType::String, InterfaceType::I32],
|
||||||
});
|
}));
|
||||||
|
|
||||||
assert_eq!(parser::parse::<Interface>(&input).unwrap(), output);
|
assert_eq!(parser::parse::<Interface>(&input).unwrap(), output);
|
||||||
}
|
}
|
||||||
|
@ -108,10 +108,24 @@ where
|
|||||||
InterfaceType::Anyref => 0x0b_u8.to_bytes(writer),
|
InterfaceType::Anyref => 0x0b_u8.to_bytes(writer),
|
||||||
InterfaceType::I32 => 0x0c_u8.to_bytes(writer),
|
InterfaceType::I32 => 0x0c_u8.to_bytes(writer),
|
||||||
InterfaceType::I64 => 0x0d_u8.to_bytes(writer),
|
InterfaceType::I64 => 0x0d_u8.to_bytes(writer),
|
||||||
|
InterfaceType::Record(record_type) => {
|
||||||
|
0x0e_u8.to_bytes(writer)?;
|
||||||
|
record_type.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.fields.to_bytes(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Encode a `TypeKind` into bytes.
|
/// Encode a `TypeKind` into bytes.
|
||||||
impl<W> ToBytes<W> for TypeKind
|
impl<W> ToBytes<W> for TypeKind
|
||||||
where
|
where
|
||||||
@ -156,7 +170,7 @@ where
|
|||||||
outputs.to_bytes(writer)?;
|
outputs.to_bytes(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::Record { fields } => {
|
Type::Record(RecordType { fields }) => {
|
||||||
TypeKind::Record.to_bytes(writer)?;
|
TypeKind::Record.to_bytes(writer)?;
|
||||||
fields.to_bytes(writer)?;
|
fields.to_bytes(writer)?;
|
||||||
}
|
}
|
||||||
@ -422,6 +436,55 @@ mod tests {
|
|||||||
assert_to_bytes!(InterfaceType::Anyref, &[0x0b]);
|
assert_to_bytes!(InterfaceType::Anyref, &[0x0b]);
|
||||||
assert_to_bytes!(InterfaceType::I32, &[0x0c]);
|
assert_to_bytes!(InterfaceType::I32, &[0x0c]);
|
||||||
assert_to_bytes!(InterfaceType::I64, &[0x0d]);
|
assert_to_bytes!(InterfaceType::I64, &[0x0d]);
|
||||||
|
assert_to_bytes!(
|
||||||
|
InterfaceType::Record(RecordType {
|
||||||
|
fields: vec![InterfaceType::String]
|
||||||
|
}),
|
||||||
|
&[0x0e, 0x01, 0x0a]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_type() {
|
||||||
|
assert_to_bytes!(
|
||||||
|
RecordType {
|
||||||
|
fields: vec![InterfaceType::String]
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
0x01, // 1 field
|
||||||
|
0x0a, // String
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_to_bytes!(
|
||||||
|
RecordType {
|
||||||
|
fields: vec![InterfaceType::String, InterfaceType::I32]
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
0x02, // 2 fields
|
||||||
|
0x0a, // String
|
||||||
|
0x0c, // I32
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_to_bytes!(
|
||||||
|
RecordType {
|
||||||
|
fields: vec![
|
||||||
|
InterfaceType::String,
|
||||||
|
InterfaceType::Record(RecordType {
|
||||||
|
fields: vec![InterfaceType::I32, InterfaceType::I32],
|
||||||
|
}),
|
||||||
|
InterfaceType::F64,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
&[
|
||||||
|
0x03, // 3 fields
|
||||||
|
0x0a, // String
|
||||||
|
0x0e, // Record
|
||||||
|
0x02, // 2 fields
|
||||||
|
0x0c, // I32
|
||||||
|
0x0c, // I32
|
||||||
|
0x09, // F64
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -471,9 +534,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_type_record() {
|
fn test_type_record() {
|
||||||
assert_to_bytes!(
|
assert_to_bytes!(
|
||||||
Type::Record {
|
Type::Record(RecordType {
|
||||||
fields: vec![InterfaceType::I32, InterfaceType::I64],
|
fields: vec![InterfaceType::I32, InterfaceType::I64],
|
||||||
},
|
}),
|
||||||
&[
|
&[
|
||||||
0x01, // record type
|
0x01, // record type
|
||||||
0x02, // list of 2 items
|
0x02, // list of 2 items
|
||||||
|
@ -61,24 +61,41 @@ use std::string::ToString;
|
|||||||
impl ToString for &InterfaceType {
|
impl ToString for &InterfaceType {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
InterfaceType::S8 => "s8".into(),
|
InterfaceType::S8 => "s8".to_string(),
|
||||||
InterfaceType::S16 => "s16".into(),
|
InterfaceType::S16 => "s16".to_string(),
|
||||||
InterfaceType::S32 => "s32".into(),
|
InterfaceType::S32 => "s32".to_string(),
|
||||||
InterfaceType::S64 => "s64".into(),
|
InterfaceType::S64 => "s64".to_string(),
|
||||||
InterfaceType::U8 => "u8".into(),
|
InterfaceType::U8 => "u8".to_string(),
|
||||||
InterfaceType::U16 => "u16".into(),
|
InterfaceType::U16 => "u16".to_string(),
|
||||||
InterfaceType::U32 => "u32".into(),
|
InterfaceType::U32 => "u32".to_string(),
|
||||||
InterfaceType::U64 => "u64".into(),
|
InterfaceType::U64 => "u64".to_string(),
|
||||||
InterfaceType::F32 => "f32".into(),
|
InterfaceType::F32 => "f32".to_string(),
|
||||||
InterfaceType::F64 => "f64".into(),
|
InterfaceType::F64 => "f64".to_string(),
|
||||||
InterfaceType::String => "string".into(),
|
InterfaceType::String => "string".to_string(),
|
||||||
InterfaceType::Anyref => "anyref".into(),
|
InterfaceType::Anyref => "anyref".to_string(),
|
||||||
InterfaceType::I32 => "i32".into(),
|
InterfaceType::I32 => "i32".to_string(),
|
||||||
InterfaceType::I64 => "i64".into(),
|
InterfaceType::I64 => "i64".to_string(),
|
||||||
|
InterfaceType::Record(record_type) => record_type.to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToString for &RecordType {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"record{fields}",
|
||||||
|
fields = self
|
||||||
|
.fields
|
||||||
|
.iter()
|
||||||
|
.fold(String::new(), |mut accumulator, interface_type| {
|
||||||
|
accumulator.push(' ');
|
||||||
|
accumulator.push_str(&format!("(field {})", &interface_type.to_string()));
|
||||||
|
accumulator
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Encode an `Instruction` into a string.
|
/// Encode an `Instruction` into a string.
|
||||||
impl ToString for &Instruction {
|
impl ToString for &Instruction {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
@ -174,15 +191,9 @@ impl<'input> ToString for &Type {
|
|||||||
outputs = output_types_to_result(&outputs),
|
outputs = output_types_to_result(&outputs),
|
||||||
),
|
),
|
||||||
|
|
||||||
Type::Record { fields } => format!(
|
Type::Record(record_type) => format!(
|
||||||
r#"(@interface type (record{fields}))"#,
|
r#"(@interface type ({record_type}))"#,
|
||||||
fields = fields
|
record_type = record_type.to_string(),
|
||||||
.iter()
|
|
||||||
.fold(String::new(), |mut accumulator, interface_type| {
|
|
||||||
accumulator.push(' ');
|
|
||||||
accumulator.push_str(&interface_type.to_string());
|
|
||||||
accumulator
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -354,10 +365,58 @@ mod tests {
|
|||||||
(&InterfaceType::Anyref).to_string(),
|
(&InterfaceType::Anyref).to_string(),
|
||||||
(&InterfaceType::I32).to_string(),
|
(&InterfaceType::I32).to_string(),
|
||||||
(&InterfaceType::I64).to_string(),
|
(&InterfaceType::I64).to_string(),
|
||||||
|
(&InterfaceType::Record(RecordType {
|
||||||
|
fields: vec![InterfaceType::String],
|
||||||
|
}))
|
||||||
|
.to_string(),
|
||||||
];
|
];
|
||||||
let outputs = vec![
|
let outputs = vec![
|
||||||
"s8", "s16", "s32", "s64", "u8", "u16", "u32", "u64", "f32", "f64", "string", "anyref",
|
"s8",
|
||||||
"i32", "i64",
|
"s16",
|
||||||
|
"s32",
|
||||||
|
"s64",
|
||||||
|
"u8",
|
||||||
|
"u16",
|
||||||
|
"u32",
|
||||||
|
"u64",
|
||||||
|
"f32",
|
||||||
|
"f64",
|
||||||
|
"string",
|
||||||
|
"anyref",
|
||||||
|
"i32",
|
||||||
|
"i64",
|
||||||
|
"record (field string)",
|
||||||
|
];
|
||||||
|
|
||||||
|
assert_eq!(inputs, outputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_record_type() {
|
||||||
|
let inputs = vec![
|
||||||
|
(&RecordType {
|
||||||
|
fields: vec![InterfaceType::String],
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
(&RecordType {
|
||||||
|
fields: vec![InterfaceType::String, InterfaceType::I32],
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
(&RecordType {
|
||||||
|
fields: vec![
|
||||||
|
InterfaceType::String,
|
||||||
|
InterfaceType::Record(RecordType {
|
||||||
|
fields: vec![InterfaceType::I32, InterfaceType::I32],
|
||||||
|
}),
|
||||||
|
InterfaceType::F64,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.to_string(),
|
||||||
|
];
|
||||||
|
let outputs = vec![
|
||||||
|
"record (field string)",
|
||||||
|
"record (field string) (field i32)",
|
||||||
|
"record (field string) (field record (field i32) (field i32)) (field f64)",
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(inputs, outputs);
|
assert_eq!(inputs, outputs);
|
||||||
@ -473,9 +532,9 @@ mod tests {
|
|||||||
outputs: vec![],
|
outputs: vec![],
|
||||||
})
|
})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
(&Type::Record {
|
(&Type::Record(RecordType {
|
||||||
fields: vec![InterfaceType::String, InterfaceType::I32],
|
fields: vec![InterfaceType::String, InterfaceType::I32],
|
||||||
})
|
}))
|
||||||
.to_string(),
|
.to_string(),
|
||||||
];
|
];
|
||||||
let outputs = vec![
|
let outputs = vec![
|
||||||
@ -487,7 +546,7 @@ mod tests {
|
|||||||
r#"(@interface type (func
|
r#"(@interface type (func
|
||||||
(result i32)))"#,
|
(result i32)))"#,
|
||||||
r#"(@interface type (func))"#,
|
r#"(@interface type (func))"#,
|
||||||
r#"(@interface type (record string i32))"#,
|
r#"(@interface type (record (field string) (field i32)))"#,
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_eq!(inputs, outputs);
|
assert_eq!(inputs, outputs);
|
||||||
|
@ -15,9 +15,9 @@ fn test_binary_encoding_decoding_roundtrip() {
|
|||||||
inputs: vec![InterfaceType::I32, InterfaceType::I32],
|
inputs: vec![InterfaceType::I32, InterfaceType::I32],
|
||||||
outputs: vec![InterfaceType::S32],
|
outputs: vec![InterfaceType::S32],
|
||||||
},
|
},
|
||||||
Type::Record {
|
Type::Record(RecordType {
|
||||||
fields: vec![InterfaceType::String, InterfaceType::I32],
|
fields: vec![InterfaceType::String, InterfaceType::I32],
|
||||||
},
|
}),
|
||||||
],
|
],
|
||||||
imports: vec![Import {
|
imports: vec![Import {
|
||||||
namespace: "a",
|
namespace: "a",
|
||||||
|
Reference in New Issue
Block a user