feat(interface-types) Re-implement Type.

The semantics of “types” have changed since the previous draft. Now, a
type is like a regular WebAssembly type but with Interface Types.
This commit is contained in:
Ivan Enderlin 2020-02-24 16:23:31 +01:00
parent 165a8ca585
commit 410d8d4476
6 changed files with 137 additions and 130 deletions

View File

@ -60,6 +60,16 @@ pub(crate) enum AdapterKind {
Export,
}
/// Represents a type signature.
#[derive(PartialEq, Debug)]
pub struct Type {
/// Types for the parameters.
pub inputs: Vec<InterfaceType>,
/// Types for the results.
pub outputs: Vec<InterfaceType>,
}
/// Represents an exported function signature.
#[derive(PartialEq, Debug)]
pub struct Export<'input> {
@ -89,55 +99,6 @@ pub struct Import<'input> {
pub output_types: Vec<InterfaceType>,
}
/// Represents a structural type.
#[derive(PartialEq, Debug)]
pub struct Type<'input> {
/// The type name.
pub name: &'input str,
/// The field names.
field_names: Vec<&'input str>,
/// The field types.
field_types: Vec<InterfaceType>,
}
impl<'input> Type<'input> {
/// Creates a new `Type`.
///
/// The constructor panics if there is the length of `names` is
/// different than the length of `types`.
pub fn new(type_name: &'input str, names: Vec<&'input str>, types: Vec<InterfaceType>) -> Self {
assert_eq!(
names.len(),
types.len(),
"There must be the same number of field names than field types."
);
Self {
name: type_name,
field_names: names,
field_types: types,
}
}
/// Adds a new field to the type.
pub fn add_field(&mut self, name: &'input str, ty: InterfaceType) {
self.field_names.push(name);
self.field_types.push(ty);
}
/// Returns the field names.
pub fn field_names(&self) -> &Vec<&'input str> {
&self.field_names
}
/// Returns the field types.
pub fn field_types(&self) -> &Vec<InterfaceType> {
&self.field_types
}
}
/// Represents an adapter.
#[derive(PartialEq, Debug)]
pub enum Adapter<'input> {
@ -179,12 +140,12 @@ pub enum Adapter<'input> {
/// definition.
#[derive(PartialEq, Default, Debug)]
pub struct Interfaces<'input> {
/// All the types.
pub types: Vec<Type>,
/// All the exported functions.
pub exports: Vec<Export<'input>>,
/// All the types.
pub types: Vec<Type<'input>>,
/// All the imported functions.
pub imports: Vec<Import<'input>>,

View File

@ -295,11 +295,10 @@ fn types<'input, E: ParseError<&'input [u8]>>(
let mut types = Vec::with_capacity(number_of_types as usize);
for _ in 0..number_of_types {
consume!((input, type_name) = string(input)?);
consume!((input, type_fields) = list(input, string)?);
consume!((input, type_types) = list(input, ty)?);
consume!((input, inputs) = list(input, ty)?);
consume!((input, outputs) = list(input, ty)?);
types.push(Type::new(type_name, type_fields, type_types));
types.push(Type { inputs, outputs });
}
Ok((input, types))
@ -424,16 +423,11 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>(
/// 0x01, // list of 1 item
/// 0x02, // S32
/// 0x01, // 1 type
/// 0x02, // string of 2 bytes
/// 0x61, 0x62, // "a", "b"
/// 0x02, // list of 2 items
/// 0x02, // string of 2 bytes
/// 0x63, 0x64, // "c", "d"
/// 0x01, // string of 1 byte
/// 0x65, // "e"
/// 0x02, // list of 2 items
/// 0x02, // S32
/// 0x02, // S32
/// 0x01, // list of 1 item
/// 0x02, // S32
/// 0x01, // 1 import
/// 0x01, // string of 1 byte
/// 0x61, // "a"
@ -464,11 +458,10 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>(
/// input_types: vec![InterfaceType::S32],
/// output_types: vec![InterfaceType::S32],
/// }],
/// types: vec![Type::new(
/// "ab",
/// vec!["cd", "e"],
/// vec![InterfaceType::S32, InterfaceType::S32],
/// )],
/// types: vec![Type {
/// inputs: vec![InterfaceType::S32, InterfaceType::S32],
/// outputs: vec![InterfaceType::S32],
/// }],
/// imports: vec![Import {
/// namespace: "a",
/// name: "b",
@ -740,24 +733,18 @@ mod tests {
fn test_types() {
let input = &[
0x01, // 1 type
0x02, // string of 2 bytes
0x61, 0x62, // "a", "b"
0x02, // list of 2 items
0x02, // string of 2 bytes
0x63, 0x64, // "c", "d"
0x01, // string of 1 byte
0x65, // "e"
0x02, // list of 2 items
0x02, // S32
0x02, // S32
0x01, // list of 2 items
0x02, // S32
];
let output = Ok((
&[] as &[u8],
vec![Type::new(
"ab",
vec!["cd", "e"],
vec![InterfaceType::S32, InterfaceType::S32],
)],
vec![Type {
inputs: vec![InterfaceType::S32, InterfaceType::S32],
outputs: vec![InterfaceType::S32],
}],
));
assert_eq!(types::<()>(input), output);
@ -863,16 +850,10 @@ mod tests {
0x01, // list of 1 item
0x0c, // I32
0x01, // 1 type
0x02, // string of 2 bytes
0x61, 0x62, // "a", "b"
0x02, // list of 2 items
0x02, // string of 2 bytes
0x63, 0x64, // "c", "d"
0x01, // string of 1 byte
0x65, // "e"
0x02, // list of 2 items
0x0c, // I32
0x0c, // I32
0x00, // list of 0 item
0x01, // 1 import
0x01, // string of 1 byte
0x61, // "a"
@ -903,11 +884,10 @@ mod tests {
input_types: vec![InterfaceType::I32],
output_types: vec![InterfaceType::I32],
}],
types: vec![Type::new(
"ab",
vec!["cd", "e"],
vec![InterfaceType::I32, InterfaceType::I32],
)],
types: vec![Type {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![],
}],
imports: vec![Import {
namespace: "a",
name: "b",

View File

@ -15,6 +15,7 @@ mod keyword {
// New keywords.
custom_keyword!(adapt);
custom_keyword!(r#type = "type");
// New types.
custom_keyword!(s8);
@ -283,8 +284,7 @@ impl Parse<'_> for FunctionType {
#[derive(PartialEq, Debug)]
enum Interface<'a> {
Export(Export<'a>),
#[allow(dead_code)]
Type(Type<'a>),
Type(Type),
Import(Import<'a>),
Adapter(Adapter<'a>),
}
@ -305,6 +305,8 @@ impl<'a> Parse<'a> for Interface<'a> {
Ok(Interface::Import(parser.parse()?))
} else if lookahead.peek::<keyword::adapt>() {
Ok(Interface::Adapter(parser.parse()?))
} else if lookahead.peek::<keyword::r#type>() {
Ok(Interface::Type(parser.parse()?))
} else {
Err(lookahead.error())
}
@ -315,6 +317,32 @@ impl<'a> Parse<'a> for Interface<'a> {
}
}
impl<'a> Parse<'a> for Type {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<keyword::r#type>()?;
let (inputs, outputs) = parser.parens(|parser| {
parser.parse::<keyword::func>()?;
let mut input_types = vec![];
let mut output_types = vec![];
while !parser.is_empty() {
let function_type = parser.parse::<FunctionType>()?;
match function_type {
FunctionType::Input(mut inputs) => input_types.append(&mut inputs),
FunctionType::Output(mut outputs) => output_types.append(&mut outputs),
}
}
Ok((input_types, output_types))
})?;
Ok(Type { inputs, outputs })
}
}
impl<'a> Parse<'a> for Export<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<keyword::export>()?;
@ -663,6 +691,17 @@ mod tests {
assert_eq!(parser::parse::<FunctionType>(&input).unwrap(), output);
}
#[test]
fn test_type() {
let input = buffer(r#"(@interface type (func (param i32 i32) (result i32)))"#);
let output = Interface::Type(Type {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::I32],
});
assert_eq!(parser::parse::<Interface>(&input).unwrap(), output);
}
#[test]
fn test_export_with_no_param_no_result() {
let input = buffer(r#"(@interface export "foo")"#);

View File

@ -147,14 +147,13 @@ where
/// Encode a `Type` into bytes.
///
/// Decoder is in `decoders::binary::types`.
impl<W> ToBytes<W> for Type<'_>
impl<W> ToBytes<W> for Type
where
W: Write,
{
fn to_bytes(&self, writer: &mut W) -> io::Result<()> {
self.name.to_bytes(writer)?;
self.field_names().to_bytes(writer)?;
self.field_types().to_bytes(writer)?;
self.inputs.to_bytes(writer)?;
self.outputs.to_bytes(writer)?;
Ok(())
}
@ -468,22 +467,16 @@ mod tests {
#[test]
fn test_type() {
assert_to_bytes!(
Type::new(
"a",
vec!["b", "c"],
vec![InterfaceType::I32, InterfaceType::I64],
),
Type {
inputs: vec![InterfaceType::I32, InterfaceType::I64],
outputs: vec![InterfaceType::S32],
},
&[
0x01, // string of length 1
0x61, // "a"
0x02, // list of 2 items
0x01, // string of length 1
0x62, // "b"
0x01, // string of length 1
0x63, // "c"
0x02, // list of 2 items
0x0c, // I32
0x0d, // I64
0x01, // list of 1 items
0x02, // I64
]
);
}
@ -571,11 +564,10 @@ mod tests {
input_types: vec![InterfaceType::I32],
output_types: vec![InterfaceType::I32],
}],
types: vec![Type::new(
"ab",
vec!["cd", "e"],
vec![InterfaceType::I32, InterfaceType::I32],
)],
types: vec![Type {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::S32],
}],
imports: vec![Import {
namespace: "a",
name: "b",
@ -599,16 +591,11 @@ mod tests {
0x01, // list of 1 item
0x0c, // I32
0x01, // 1 type
0x02, // string of 2 bytes
0x61, 0x62, // "a", "b"
0x02, // list of 2 items
0x02, // string of 2 bytes
0x63, 0x64, // "c", "d"
0x01, // string of 1 byte
0x65, // "e"
0x02, // list of 2 items
0x0c, // I32
0x0c, // I32
0x01, // list of 1 item
0x02, // S32
0x01, // 1 import
0x01, // string of 1 byte
0x61, // "a"

View File

@ -211,9 +211,13 @@ impl<'input> ToString for &Export<'input> {
}
/// Encode a `Type` into a string.
impl<'input> ToString for &Type<'input> {
impl<'input> ToString for &Type {
fn to_string(&self) -> String {
todo!("To be implemented.")
format!(
r#"(@interface type (func{inputs}{outputs}))"#,
inputs = input_types_to_param(&self.inputs),
outputs = output_types_to_result(&self.outputs),
)
}
}
@ -297,7 +301,6 @@ impl<'input> ToString for &Interfaces<'input> {
.types
.iter()
.fold(String::new(), |mut accumulator, ty| {
accumulator.push_str(&format!("\n\n;; Interface, Ty {}\n", ty.name));
accumulator.push_str(&ty.to_string());
accumulator
});
@ -426,6 +429,44 @@ mod tests {
assert_eq!(inputs, outputs);
}
#[test]
fn test_types() {
let inputs: Vec<String> = vec![
(&Type {
inputs: vec![InterfaceType::I32, InterfaceType::F32],
outputs: vec![InterfaceType::I32],
})
.to_string(),
(&Type {
inputs: vec![InterfaceType::I32],
outputs: vec![],
})
.to_string(),
(&Type {
inputs: vec![],
outputs: vec![InterfaceType::I32],
})
.to_string(),
(&Type {
inputs: vec![],
outputs: vec![],
})
.to_string(),
];
let outputs = vec![
r#"(@interface type (func
(param i32 f32)
(result i32)))"#,
r#"(@interface type (func
(param i32)))"#,
r#"(@interface type (func
(result i32)))"#,
r#"(@interface type (func))"#,
];
assert_eq!(inputs, outputs);
}
#[test]
fn test_exports() {
let inputs: Vec<String> = vec![

View File

@ -11,11 +11,10 @@ fn test_binary_encoding_decoding_roundtrip() {
input_types: vec![InterfaceType::I32],
output_types: vec![InterfaceType::I32],
}],
types: vec![Type::new(
"ab",
vec!["cd", "e"],
vec![InterfaceType::I32, InterfaceType::I32],
)],
types: vec![Type {
inputs: vec![InterfaceType::I32, InterfaceType::I32],
outputs: vec![InterfaceType::S32],
}],
imports: vec![Import {
namespace: "a",
name: "b",