From d4c01e8ddcbc030313569029e7deedfaa8db70c5 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 26 Feb 2020 15:32:14 +0100 Subject: [PATCH] test(interface-types) Fix all tests based on previous commits. --- src/ast.rs | 20 +- src/decoders/binary.rs | 265 ++++++++++++------------- src/decoders/wat.rs | 282 +++++++------------------- src/encoders/binary.rs | 156 +++++---------- src/encoders/wat.rs | 435 +++++++++++++---------------------------- tests/binary.rs | 37 ++-- 6 files changed, 413 insertions(+), 782 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 49a33d5..f34d894 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -83,16 +83,6 @@ pub struct Export<'input> { pub function_type: u32, } -/// Represents an implementation. -#[derive(PartialEq, Debug)] -pub struct Implementation { - /// The core function type. - pub core_function_type: u32, - - /// The adapter function type. - pub adapter_function_type: u32, -} - /// Represents an adapter. #[derive(PartialEq, Debug)] pub struct Adapter<'input> { @@ -103,6 +93,16 @@ pub struct Adapter<'input> { pub instructions: Vec>, } +/// Represents an implementation. +#[derive(PartialEq, Debug)] +pub struct Implementation { + /// The core function type. + pub core_function_type: u32, + + /// The adapter function type. + pub adapter_function_type: u32, +} + /// Represents the kind of interface. #[derive(PartialEq, Debug)] pub(crate) enum InterfaceKind { diff --git a/src/decoders/binary.rs b/src/decoders/binary.rs index 3372153..883afad 100644 --- a/src/decoders/binary.rs +++ b/src/decoders/binary.rs @@ -376,41 +376,43 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>( ) -> IResult<&'input [u8], Interfaces, E> { let mut input = bytes; - consume!((input, interface_kind) = byte(input)?); - - let interface_kind = InterfaceKind::try_from(interface_kind) - .map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?; - let mut all_types = vec![]; let mut all_imports = vec![]; let mut all_adapters = vec![]; let mut all_exports = vec![]; let mut all_implementations = vec![]; - match interface_kind { - InterfaceKind::Type => { - consume!((input, mut new_types) = types(input)?); - all_types.append(&mut new_types); - } + while !input.is_empty() { + consume!((input, interface_kind) = byte(input)?); - InterfaceKind::Import => { - consume!((input, mut new_imports) = imports(input)?); - all_imports.append(&mut new_imports); - } + let interface_kind = InterfaceKind::try_from(interface_kind) + .map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?; - InterfaceKind::Adapter => { - consume!((input, mut new_adapters) = adapters(input)?); - all_adapters.append(&mut new_adapters); - } + match interface_kind { + InterfaceKind::Type => { + consume!((input, mut new_types) = types(input)?); + all_types.append(&mut new_types); + } - InterfaceKind::Export => { - consume!((input, mut new_exports) = exports(input)?); - all_exports.append(&mut new_exports); - } + InterfaceKind::Import => { + consume!((input, mut new_imports) = imports(input)?); + all_imports.append(&mut new_imports); + } - InterfaceKind::Implementation => { - consume!((input, mut new_implementations) = implementations(input)?); - all_implementations.append(&mut new_implementations) + InterfaceKind::Adapter => { + consume!((input, mut new_adapters) = adapters(input)?); + all_adapters.append(&mut new_adapters); + } + + InterfaceKind::Export => { + consume!((input, mut new_exports) = exports(input)?); + all_exports.append(&mut new_exports); + } + + InterfaceKind::Implementation => { + consume!((input, mut new_implementations) = implementations(input)?); + all_implementations.append(&mut new_implementations) + } } } @@ -441,66 +443,62 @@ fn interfaces<'input, E: ParseError<&'input [u8]>>( /// /// # fn main() { /// let input = &[ +/// 0x00, // type section +/// 0x01, // 1 type +/// 0x01, // list of 1 item +/// 0x00, // S8 +/// 0x01, // list of 1 item +/// 0x01, // S16 +/// // +/// 0x01, // import section +/// 0x01, // 1 import +/// 0x02, // string of 2 bytes +/// 0x61, 0x62, // "a", "b" +/// 0x01, // string of 1 byte +/// 0x63, // "c" +/// 0x00, // signature type +/// // +/// 0x02, // adapter section +/// 0x01, // 1 adapter +/// 0x00, // function type +/// 0x01, // list of 1 item +/// 0x00, 0x01, // ArgumentGet { index: 1 } +/// // +/// 0x03, // export section /// 0x01, // 1 export /// 0x02, // string of 2 bytes /// 0x61, 0x62, // "a", "b" -/// 0x01, // list of 1 item -/// 0x02, // S32 -/// 0x01, // list of 1 item -/// 0x02, // S32 -/// 0x01, // 1 type -/// 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" -/// 0x01, // string of 1 byte -/// 0x62, // "b" -/// 0x01, // list of 1 item -/// 0x02, // S32 -/// 0x01, // list of 1 item -/// 0x03, // S64 -/// 0x01, // 1 adapter -/// 0x00, // adapter kind: import -/// 0x01, // string of 1 byte -/// 0x61, // "a" -/// 0x01, // string of 1 byte -/// 0x62, // "b" -/// 0x01, // list of 1 item -/// 0x02, // S32 -/// 0x01, // list of 1 item -/// 0x02, // S32 -/// 0x01, // list of 1 item -/// 0x00, 0x01, // ArgumentGet { index: 1 } +/// 0x01, // function type +/// // +/// 0x04, // implementation section +/// 0x01, // 1 implementation +/// 0x02, // core function type +/// 0x03, // adapter function type /// ]; /// let output = Ok(( /// &[] as &[u8], /// Interfaces { -/// exports: vec![Export { -/// name: "ab", -/// input_types: vec![InterfaceType::S32], -/// output_types: vec![InterfaceType::S32], -/// }], /// types: vec![Type { -/// inputs: vec![InterfaceType::S32, InterfaceType::S32], -/// outputs: vec![InterfaceType::S32], +/// inputs: vec![InterfaceType::S8], +/// outputs: vec![InterfaceType::S16], /// }], /// imports: vec![Import { -/// namespace: "a", -/// name: "b", -/// input_types: vec![InterfaceType::S32], -/// output_types: vec![InterfaceType::S64], +/// namespace: "ab", +/// name: "c", +/// signature_type: 0, /// }], -/// adapters: vec![Adapter::Import { -/// namespace: "a", -/// name: "b", -/// input_types: vec![InterfaceType::S32], -/// output_types: vec![InterfaceType::S32], +/// adapters: vec![Adapter { +/// function_type: 0, /// instructions: vec![Instruction::ArgumentGet { index: 1 }], /// }], +/// exports: vec![Export { +/// name: "ab", +/// function_type: 1, +/// }], +/// implementations: vec![Implementation { +/// core_function_type: 2, +/// adapter_function_type: 3, +/// }], /// }, /// )); /// @@ -727,27 +725,21 @@ mod tests { 0x02, // 2 exports 0x02, // string of 2 bytes 0x61, 0x62, // "a", "b" - 0x01, // list of 1 item - 0x00, // S8 - 0x01, // list of 1 item - 0x00, // S8 + 0x01, // function type 0x02, // string of 2 bytes 0x63, 0x64, // "c", "d" - 0x00, // list of 0 item - 0x00, // list of 0 item + 0x02, // function type ]; let output = Ok(( &[] as &[u8], vec![ Export { name: "ab", - input_types: vec![InterfaceType::S8], - output_types: vec![InterfaceType::S8], + function_type: 1, }, Export { name: "cd", - input_types: vec![], - output_types: vec![], + function_type: 2, }, ], )); @@ -784,18 +776,12 @@ mod tests { 0x61, // "a" 0x01, // string of 1 byte 0x62, // "b" - 0x01, // list of 1 item - 0x02, // S32 - 0x01, // list of 1 item - 0x03, // S64 + 0x01, // signature type 0x01, // string of 1 byte 0x63, // "c" 0x01, // string of 1 byte 0x64, // "d" - 0x01, // list of 1 item - 0x02, // S32 - 0x01, // list of 1 item - 0x03, // S64 + 0x02, // signature type ]; let output = Ok(( &[] as &[u8], @@ -803,14 +789,12 @@ mod tests { Import { namespace: "a", name: "b", - input_types: vec![InterfaceType::S32], - output_types: vec![InterfaceType::S64], + signature_type: 1, }, Import { namespace: "c", name: "d", - input_types: vec![InterfaceType::S32], - output_types: vec![InterfaceType::S64], + signature_type: 2, }, ], )); @@ -870,67 +854,62 @@ mod tests { #[test] fn test_parse() { let input = &[ + 0x00, // type section + 0x01, // 1 type + 0x01, // list of 1 item + 0x00, // S8 + 0x01, // list of 1 item + 0x01, // S16 + // + 0x01, // import section + 0x01, // 1 import + 0x02, // string of 2 bytes + 0x61, 0x62, // "a", "b" + 0x01, // string of 1 byte + 0x63, // "c" + 0x00, // signature type + // + 0x02, // adapter section + 0x01, // 1 adapter + 0x00, // function type + 0x01, // list of 1 item + 0x00, 0x01, // ArgumentGet { index: 1 } + // + 0x03, // export section 0x01, // 1 export 0x02, // string of 2 bytes 0x61, 0x62, // "a", "b" - 0x01, // list of 1 item - 0x0c, // I32 - 0x01, // list of 1 item - 0x0c, // I32 - 0x01, // 1 type - 0x02, // list of 2 items - 0x0c, // I32 - 0x0c, // I32 - 0x00, // list of 0 item - 0x01, // 1 import - 0x01, // string of 1 byte - 0x61, // "a" - 0x01, // string of 1 byte - 0x62, // "b" - 0x01, // list of 1 item - 0x0c, // I32 - 0x01, // list of 1 item - 0x0d, // I64 - /* - 0x01, // 1 adapter - 0x00, // adapter kind: import - 0x01, // string of 1 byte - 0x61, // "a" - 0x01, // string of 1 byte - 0x62, // "b" - 0x01, // list of 1 item - 0x0c, // I32 - 0x01, // list of 1 item - 0x0c, // I32 - 0x01, // list of 1 item - 0x00, 0x01, // ArgumentGet { index: 1 } - */ + 0x01, // function type + // + 0x04, // implementation section + 0x01, // 1 implementation + 0x02, // core function type + 0x03, // adapter function type ]; let output = Ok(( &[] as &[u8], Interfaces { - exports: vec![Export { - name: "ab", - input_types: vec![InterfaceType::I32], - output_types: vec![InterfaceType::I32], - }], types: vec![Type { - inputs: vec![InterfaceType::I32, InterfaceType::I32], - outputs: vec![], + inputs: vec![InterfaceType::S8], + outputs: vec![InterfaceType::S16], }], imports: vec![Import { - namespace: "a", - name: "b", - input_types: vec![InterfaceType::I32], - output_types: vec![InterfaceType::I64], + namespace: "ab", + name: "c", + signature_type: 0, }], - adapters: vec![/*Adapter::Import { - namespace: "a", - name: "b", - input_types: vec![InterfaceType::I32], - output_types: vec![InterfaceType::I32], + adapters: vec![Adapter { + function_type: 0, instructions: vec![Instruction::ArgumentGet { index: 1 }], - }*/], + }], + exports: vec![Export { + name: "ab", + function_type: 1, + }], + implementations: vec![Implementation { + core_function_type: 2, + adapter_function_type: 3, + }], }, )); diff --git a/src/decoders/wat.rs b/src/decoders/wat.rs index 2f96ca4..5c92e32 100644 --- a/src/decoders/wat.rs +++ b/src/decoders/wat.rs @@ -470,67 +470,39 @@ impl<'a> Parse<'a> for Interfaces<'a> { /// /// # fn main() { /// let input = Buffer::new( -/// r#"(@interface export "foo" -/// (param i32)) +/// r#"(@interface type (func (param i32) (result s8))) /// -/// (@interface export "bar") +/// (@interface import "ns" "foo" (func (type 0))) /// -/// (@interface func $ns_foo (import "ns" "foo") -/// (result i32)) +/// (@interface func (type 0) arg.get 42) /// -/// (@interface func $ns_bar (import "ns" "bar")) +/// (@interface export "bar" (func 0)) /// -/// (@interface adapt (import "ns" "foo") -/// (param i32) -/// arg.get 42) -/// -/// (@interface adapt (export "bar") -/// arg.get 42)"#, +/// (@interface implement (func 0) (func 1))"#, /// ) /// .unwrap(); /// let output = Interfaces { -/// exports: vec![ -/// Export { -/// name: "foo", -/// input_types: vec![InterfaceType::I32], -/// output_types: vec![], -/// }, -/// Export { -/// name: "bar", -/// input_types: vec![], -/// output_types: vec![], -/// }, -/// ], -/// types: vec![], -/// imports: vec![ -/// Import { -/// namespace: "ns", -/// name: "foo", -/// input_types: vec![], -/// output_types: vec![InterfaceType::I32], -/// }, -/// Import { -/// namespace: "ns", -/// name: "bar", -/// input_types: vec![], -/// output_types: vec![], -/// }, -/// ], -/// adapters: vec![ -/// Adapter::Import { -/// namespace: "ns", -/// name: "foo", -/// input_types: vec![InterfaceType::I32], -/// output_types: vec![], -/// instructions: vec![Instruction::ArgumentGet { index: 42 }], -/// }, -/// Adapter::Export { -/// name: "bar", -/// input_types: vec![], -/// output_types: vec![], -/// instructions: vec![Instruction::ArgumentGet { index: 42 }], -/// }, -/// ], +/// types: vec![Type { +/// inputs: vec![InterfaceType::I32], +/// outputs: vec![InterfaceType::S8], +/// }], +/// imports: vec![Import { +/// namespace: "ns", +/// name: "foo", +/// signature_type: 0, +/// }], +/// adapters: vec![Adapter { +/// function_type: 0, +/// instructions: vec![Instruction::ArgumentGet { index: 42 }], +/// }], +/// exports: vec![Export { +/// name: "bar", +/// function_type: 0, +/// }], +/// implementations: vec![Implementation { +/// core_function_type: 0, +/// adapter_function_type: 1, +/// }], /// }; /// /// assert_eq!(parse(&input).unwrap(), output); @@ -685,48 +657,11 @@ mod tests { } #[test] - fn test_export_with_no_param_no_result() { - let input = buffer(r#"(@interface export "foo")"#); + fn test_export() { + let input = buffer(r#"(@interface export "foo" (func 0))"#); let output = Interface::Export(Export { name: "foo", - input_types: vec![], - output_types: vec![], - }); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_export_with_some_param_no_result() { - let input = buffer(r#"(@interface export "foo" (param i32))"#); - let output = Interface::Export(Export { - name: "foo", - input_types: vec![InterfaceType::I32], - output_types: vec![], - }); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_export_with_no_param_some_result() { - let input = buffer(r#"(@interface export "foo" (result i32))"#); - let output = Interface::Export(Export { - name: "foo", - input_types: vec![], - output_types: vec![InterfaceType::I32], - }); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_export_with_some_param_some_result() { - let input = buffer(r#"(@interface export "foo" (param string) (result i32 i32))"#); - let output = Interface::Export(Export { - name: "foo", - input_types: vec![InterfaceType::String], - output_types: vec![InterfaceType::I32, InterfaceType::I32], + function_type: 0, }); assert_eq!(parser::parse::(&input).unwrap(), output); @@ -734,93 +669,44 @@ mod tests { #[test] fn test_export_escaped_name() { - let input = buffer(r#"(@interface export "fo\"o")"#); + let input = buffer(r#"(@interface export "fo\"o" (func 0))"#); let output = Interface::Export(Export { name: r#"fo"o"#, - input_types: vec![], - output_types: vec![], + function_type: 0, }); assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] - fn test_import_with_no_param_no_result() { - let input = buffer(r#"(@interface func $ns_foo (import "ns" "foo"))"#); + fn test_import() { + let input = buffer(r#"(@interface import "ns" "foo" (func (type 0)))"#); let output = Interface::Import(Import { namespace: "ns", name: "foo", - input_types: vec![], - output_types: vec![], + signature_type: 0, }); assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] - fn test_import_with_some_param_no_result() { - let input = buffer(r#"(@interface func $ns_foo (import "ns" "foo") (param i32))"#); - let output = Interface::Import(Import { - namespace: "ns", - name: "foo", - input_types: vec![InterfaceType::I32], - output_types: vec![], + fn test_adapter() { + let input = buffer(r#"(@interface func (type 0) arg.get 42)"#); + let output = Interface::Adapter(Adapter { + function_type: 0, + instructions: vec![Instruction::ArgumentGet { index: 42 }], }); assert_eq!(parser::parse::(&input).unwrap(), output); } #[test] - fn test_import_with_no_param_some_result() { - let input = buffer(r#"(@interface func $ns_foo (import "ns" "foo") (result i32))"#); - let output = Interface::Import(Import { - namespace: "ns", - name: "foo", - input_types: vec![], - output_types: vec![InterfaceType::I32], - }); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_import_with_some_param_some_result() { - let input = buffer( - r#"(@interface func $ns_foo (import "ns" "foo") (param string) (result i32 i32))"#, - ); - let output = Interface::Import(Import { - namespace: "ns", - name: "foo", - input_types: vec![InterfaceType::String], - output_types: vec![InterfaceType::I32, InterfaceType::I32], - }); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_adapter_import() { - let input = - buffer(r#"(@interface adapt (import "ns" "foo") (param i32 i32) (result i32))"#); - let output = Interface::Adapter(Adapter::Import { - namespace: "ns", - name: "foo", - input_types: vec![InterfaceType::I32, InterfaceType::I32], - output_types: vec![InterfaceType::I32], - instructions: vec![], - }); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_adapter_export() { - let input = buffer(r#"(@interface adapt (export "foo") (param i32 i32) (result i32))"#); - let output = Interface::Adapter(Adapter::Export { - name: "foo", - input_types: vec![InterfaceType::I32, InterfaceType::I32], - output_types: vec![InterfaceType::I32], - instructions: vec![], + fn test_implementation() { + let input = buffer(r#"(@interface implement (func 0) (func 1))"#); + let output = Interface::Implementation(Implementation { + core_function_type: 0, + adapter_function_type: 1, }); assert_eq!(parser::parse::(&input).unwrap(), output); @@ -829,66 +715,38 @@ mod tests { #[test] fn test_interfaces() { let input = buffer( - r#"(@interface export "foo" - (param i32)) + r#"(@interface type (func (param i32) (result s8))) -(@interface export "bar") +(@interface import "ns" "foo" (func (type 0))) -(@interface func $ns_foo (import "ns" "foo") - (result i32)) +(@interface func (type 0) arg.get 42) -(@interface func $ns_bar (import "ns" "bar")) +(@interface export "bar" (func 0)) -(@interface adapt (import "ns" "foo") - (param i32) - arg.get 42) - -(@interface adapt (export "bar") - arg.get 42)"#, +(@interface implement (func 0) (func 1))"#, ); let output = Interfaces { - exports: vec![ - Export { - name: "foo", - input_types: vec![InterfaceType::I32], - output_types: vec![], - }, - Export { - name: "bar", - input_types: vec![], - output_types: vec![], - }, - ], - types: vec![], - imports: vec![ - Import { - namespace: "ns", - name: "foo", - input_types: vec![], - output_types: vec![InterfaceType::I32], - }, - Import { - namespace: "ns", - name: "bar", - input_types: vec![], - output_types: vec![], - }, - ], - adapters: vec![ - Adapter::Import { - namespace: "ns", - name: "foo", - input_types: vec![InterfaceType::I32], - output_types: vec![], - instructions: vec![Instruction::ArgumentGet { index: 42 }], - }, - Adapter::Export { - name: "bar", - input_types: vec![], - output_types: vec![], - instructions: vec![Instruction::ArgumentGet { index: 42 }], - }, - ], + types: vec![Type { + inputs: vec![InterfaceType::I32], + outputs: vec![InterfaceType::S8], + }], + imports: vec![Import { + namespace: "ns", + name: "foo", + signature_type: 0, + }], + adapters: vec![Adapter { + function_type: 0, + instructions: vec![Instruction::ArgumentGet { index: 42 }], + }], + exports: vec![Export { + name: "bar", + function_type: 0, + }], + implementations: vec![Implementation { + core_function_type: 0, + adapter_function_type: 1, + }], }; assert_eq!(parser::parse::(&input).unwrap(), output); diff --git a/src/encoders/binary.rs b/src/encoders/binary.rs index e15f7d6..c4f5b53 100644 --- a/src/encoders/binary.rs +++ b/src/encoders/binary.rs @@ -237,8 +237,6 @@ where self.implementations.to_bytes(writer)?; } - //self.adapters.to_bytes(writer)?; - Ok(()) } } @@ -448,7 +446,7 @@ mod tests { fn test_interface_kind() { assert_to_bytes!(InterfaceKind::Type, &[0x00]); assert_to_bytes!(InterfaceKind::Import, &[0x01]); - assert_to_bytes!(InterfaceKind::Function, &[0x02]); + assert_to_bytes!(InterfaceKind::Adapter, &[0x02]); assert_to_bytes!(InterfaceKind::Export, &[0x03]); assert_to_bytes!(InterfaceKind::Implementation, &[0x04]); } @@ -458,19 +456,14 @@ mod tests { assert_to_bytes!( Export { name: "abc", - input_types: vec![InterfaceType::I32, InterfaceType::I64], - output_types: vec![InterfaceType::I32] + function_type: 0, }, &[ 0x03, // string of length 3 0x61, // "a" 0x62, // "b" 0x63, // "c" - 0x02, // list of 2 items - 0x0c, // I32 - 0x0d, // I64 - 0x01, // list of 1 items - 0x0c, // I32 + 0x00, // function type ] ); } @@ -498,68 +491,27 @@ mod tests { Import { namespace: "a", name: "b", - input_types: vec![InterfaceType::I32, InterfaceType::I64], - output_types: vec![InterfaceType::I32], + signature_type: 0, }, &[ 0x01, // string of length 1 0x61, // "a" 0x01, // string of length 1 0x62, // "b" - 0x02, // list of 2 items - 0x0c, // I32 - 0x0d, // I64 - 0x01, // list of 1 items - 0x0c, // I32 + 0x00, // signature typr ] ); } #[test] - fn test_adapter_import() { + fn test_adapter() { assert_to_bytes!( - Adapter::Import { - namespace: "a", - name: "b", - input_types: vec![InterfaceType::I32, InterfaceType::I64], - output_types: vec![InterfaceType::I32], + Adapter { + function_type: 0, instructions: vec![Instruction::ArgumentGet { index: 1 }], }, &[ - 0x01, // InterfaceKind::Import - 0x01, // string of length 1 - 0x61, // "a" - 0x01, // string of length 1 - 0x62, // "b" - 0x02, // list of 2 items - 0x0c, // I32 - 0x0d, // I64 - 0x01, // list of 1 items - 0x0c, // I32 - 0x01, // list of 1 item - 0x00, 0x01, // ArgumentGet { index: 1 } - ] - ); - } - - #[test] - fn test_adapter_export() { - assert_to_bytes!( - Adapter::Export { - name: "a", - input_types: vec![InterfaceType::I32, InterfaceType::I64], - output_types: vec![InterfaceType::I32], - instructions: vec![Instruction::ArgumentGet { index: 1 }], - }, - &[ - 0x03, // InterfaceKind::Export - 0x01, // string of length 1 - 0x61, // "a" - 0x02, // list of 2 items - 0x0c, // I32 - 0x0d, // I64 - 0x01, // list of 1 items - 0x0c, // I32 + 0x00, // function type 0x01, // list of 1 item 0x00, 0x01, // ArgumentGet { index: 1 } ] @@ -570,64 +522,60 @@ mod tests { fn test_interfaces() { assert_to_bytes!( Interfaces { - exports: vec![Export { - name: "ab", - input_types: vec![InterfaceType::I32], - output_types: vec![InterfaceType::I32], - }], types: vec![Type { - inputs: vec![InterfaceType::I32, InterfaceType::I32], - outputs: vec![InterfaceType::S32], + inputs: vec![InterfaceType::S8], + outputs: vec![InterfaceType::S16], }], imports: vec![Import { - namespace: "a", - name: "b", - input_types: vec![InterfaceType::I32], - output_types: vec![InterfaceType::I64], + namespace: "ab", + name: "c", + signature_type: 0, }], - adapters: vec![Adapter::Import { - namespace: "a", - name: "b", - input_types: vec![InterfaceType::I32], - output_types: vec![InterfaceType::I32], + adapters: vec![Adapter { + function_type: 0, instructions: vec![Instruction::ArgumentGet { index: 1 }], }], + exports: vec![Export { + name: "ab", + function_type: 1, + }], + implementations: vec![Implementation { + core_function_type: 2, + adapter_function_type: 3, + }], }, &[ + 0x00, // type section + 0x01, // 1 type + 0x01, // list of 1 item + 0x00, // S8 + 0x01, // list of 1 item + 0x01, // S16 + // + 0x01, // import section + 0x01, // 1 import + 0x02, // string of 2 bytes + 0x61, 0x62, // "a", "b" + 0x01, // string of 1 byte + 0x63, // "c" + 0x00, // signature type + // + 0x02, // adapter section + 0x01, // 1 adapter + 0x00, // function type + 0x01, // list of 1 item + 0x00, 0x01, // ArgumentGet { index: 1 } + // + 0x03, // export section 0x01, // 1 export 0x02, // string of 2 bytes 0x61, 0x62, // "a", "b" - 0x01, // list of 1 item - 0x0c, // I32 - 0x01, // list of 1 item - 0x0c, // I32 - 0x01, // 1 type - 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" - 0x01, // string of 1 byte - 0x62, // "b" - 0x01, // list of 1 item - 0x0c, // I32 - 0x01, // list of 1 item - 0x0d, // I64 - 0x01, // 1 adapter - 0x00, // adapter kind: import - 0x01, // string of 1 byte - 0x61, // "a" - 0x01, // string of 1 byte - 0x62, // "b" - 0x01, // list of 1 item - 0x0c, // I32 - 0x01, // list of 1 item - 0x0c, // I32 - 0x01, // list of 1 item - 0x00, 0x01, // ArgumentGet { index: 1 } + 0x01, // function type + // + 0x04, // implementation section + 0x01, // 1 implementation + 0x02, // core function type + 0x03, // adapter function type ] ); } diff --git a/src/encoders/wat.rs b/src/encoders/wat.rs index 44c3287..7d0c2ca 100644 --- a/src/encoders/wat.rs +++ b/src/encoders/wat.rs @@ -11,74 +11,46 @@ //! //! # fn main() { //! let input: String = (&Interfaces { -//! exports: vec![ -//! Export { -//! name: "foo", -//! input_types: vec![InterfaceType::I32], -//! output_types: vec![], -//! }, -//! Export { -//! name: "bar", -//! input_types: vec![], -//! output_types: vec![], -//! }, -//! ], -//! types: vec![], -//! imports: vec![ -//! Import { -//! namespace: "ns", -//! name: "foo", -//! input_types: vec![], -//! output_types: vec![InterfaceType::I32], -//! }, -//! Import { -//! namespace: "ns", -//! name: "bar", -//! input_types: vec![], -//! output_types: vec![], -//! }, -//! ], -//! adapters: vec![ -//! Adapter::Import { -//! namespace: "ns", -//! name: "foo", -//! input_types: vec![InterfaceType::I32], -//! output_types: vec![], -//! instructions: vec![Instruction::ArgumentGet { index: 42 }], -//! }, -//! Adapter::Export { -//! name: "bar", -//! input_types: vec![], -//! output_types: vec![], -//! instructions: vec![Instruction::ArgumentGet { index: 42 }], -//! }, -//! ], +//! types: vec![Type { +//! inputs: vec![InterfaceType::I32], +//! outputs: vec![InterfaceType::S8], +//! }], +//! imports: vec![Import { +//! namespace: "ns", +//! name: "foo", +//! signature_type: 0, +//! }], +//! adapters: vec![Adapter { +//! function_type: 0, +//! instructions: vec![Instruction::ArgumentGet { index: 42 }], +//! }], +//! exports: vec![Export { +//! name: "bar", +//! function_type: 0, +//! }], +//! implementations: vec![Implementation { +//! core_function_type: 0, +//! adapter_function_type: 1, +//! }], //! }) //! .to_string(); -//! let output = r#";; Interfaces -//! -//! ;; Interface, Export foo -//! (@interface export "foo" -//! (param i32)) -//! -//! ;; Interface, Export bar -//! (@interface export "bar") -//! -//! ;; Interface, Import ns.foo -//! (@interface func $ns_foo (import "ns" "foo") -//! (result i32)) -//! -//! ;; Interface, Import ns.bar -//! (@interface func $ns_bar (import "ns" "bar")) -//! -//! ;; Interface, Adapter ns.foo -//! (@interface adapt (import "ns" "foo") +//! let output = r#";; Types +//! (@interface type (func //! (param i32) +//! (result s8))) +//! +//! ;; Imports +//! (@interface import "ns" "foo" (func (type 0))) +//! +//! ;; Adapters +//! (@interface func (type 0) //! arg.get 42) //! -//! ;; Interface, Adapter bar -//! (@interface adapt (export "bar") -//! arg.get 42)"#; +//! ;; Exports +//! (@interface export "bar" (func 0)) +//! +//! ;; Implementations +//! (@interface implement (func 0) (func 1))"#; //! //! assert_eq!(input, output); //! # } @@ -261,12 +233,13 @@ impl<'input> ToString for &Implementation { /// Encode an `Interfaces` into a string. impl<'input> ToString for &Interfaces<'input> { fn to_string(&self) -> String { - let mut output = String::from(";; Interfaces"); + 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 }); @@ -275,6 +248,7 @@ impl<'input> ToString for &Interfaces<'input> { .imports .iter() .fold(String::new(), |mut accumulator, import| { + accumulator.push('\n'); accumulator.push_str(&import.to_string()); accumulator }); @@ -283,6 +257,7 @@ impl<'input> ToString for &Interfaces<'input> { .adapters .iter() .fold(String::new(), |mut accumulator, adapter| { + accumulator.push('\n'); accumulator.push_str(&adapter.to_string()); accumulator }); @@ -291,6 +266,7 @@ impl<'input> ToString for &Interfaces<'input> { .exports .iter() .fold(String::new(), |mut accumulator, export| { + accumulator.push('\n'); accumulator.push_str(&export.to_string()); accumulator }); @@ -299,15 +275,49 @@ impl<'input> ToString for &Interfaces<'input> { self.implementations .iter() .fold(String::new(), |mut accumulator, implementation| { + accumulator.push('\n'); accumulator.push_str(&implementation.to_string()); accumulator }); - output.push_str(&types); - output.push_str(&imports); - output.push_str(&adapters); - output.push_str(&exports); - output.push_str(&implementations); + let separator = |output: &mut String| { + if !output.is_empty() { + output.push_str("\n\n"); + } + }; + + if !types.is_empty() { + output.push_str(";; Types"); + output.push_str(&types); + } + + separator(&mut output); + + if !imports.is_empty() { + output.push_str(";; Imports"); + output.push_str(&imports); + } + + separator(&mut output); + + if !adapters.is_empty() { + output.push_str(";; Adapters"); + output.push_str(&adapters); + } + + separator(&mut output); + + if !exports.is_empty() { + output.push_str(";; Exports"); + output.push_str(&exports); + } + + separator(&mut output); + + if !implementations.is_empty() { + output.push_str(";; Implementations"); + output.push_str(&implementations); + } output } @@ -436,254 +446,85 @@ mod tests { #[test] fn test_exports() { - let inputs: Vec = vec![ - (&Export { - name: "foo", - input_types: vec![InterfaceType::I32, InterfaceType::F32], - output_types: vec![InterfaceType::I32], - }) - .to_string(), - (&Export { - name: "foo", - input_types: vec![InterfaceType::I32], - output_types: vec![], - }) - .to_string(), - (&Export { - name: "foo", - input_types: vec![], - output_types: vec![InterfaceType::I32], - }) - .to_string(), - (&Export { - name: "foo", - input_types: vec![], - output_types: vec![], - }) - .to_string(), - ]; - let outputs = vec![ - r#"(@interface export "foo" - (param i32 f32) - (result i32))"#, - r#"(@interface export "foo" - (param i32))"#, - r#"(@interface export "foo" - (result i32))"#, - r#"(@interface export "foo")"#, - ]; + let input = (&Export { + name: "foo", + function_type: 0, + }) + .to_string(); + let output = r#"(@interface export "foo" (func 0))"#; - assert_eq!(inputs, outputs); + assert_eq!(input, output); } #[test] fn test_imports() { - let inputs: Vec = vec![ - (&Import { - namespace: "ns", - name: "foo", - input_types: vec![InterfaceType::I32, InterfaceType::String], - output_types: vec![InterfaceType::String], - }) - .to_string(), - (&Import { - namespace: "ns", - name: "foo", - input_types: vec![InterfaceType::String], - output_types: vec![], - }) - .to_string(), - (&Import { - namespace: "ns", - name: "foo", - input_types: vec![], - output_types: vec![InterfaceType::String], - }) - .to_string(), - (&Import { - namespace: "ns", - name: "foo", - input_types: vec![], - output_types: vec![], - }) - .to_string(), - ]; - let outputs = vec![ - r#"(@interface func $ns_foo (import "ns" "foo") - (param i32 string) - (result string))"#, - r#"(@interface func $ns_foo (import "ns" "foo") - (param string))"#, - r#"(@interface func $ns_foo (import "ns" "foo") - (result string))"#, - r#"(@interface func $ns_foo (import "ns" "foo"))"#, - ]; + let input = (&Import { + namespace: "ns", + name: "foo", + signature_type: 0, + }) + .to_string(); + let output = r#"(@interface import "ns" "foo" (func (type 0)))"#; - assert_eq!(inputs, outputs); + assert_eq!(input, output); } #[test] - fn test_adapters() { - let inputs: Vec = vec![ - (&Adapter::Import { - namespace: "ns", - name: "foo", - input_types: vec![InterfaceType::I32, InterfaceType::F32], - output_types: vec![InterfaceType::I32], - instructions: vec![ - Instruction::ArgumentGet { index: 0 }, - Instruction::WriteUtf8 { - allocator_name: "hello", - }, - Instruction::CallExport { export_name: "f" }, - ], - }) - .to_string(), - (&Adapter::Import { - namespace: "ns", - name: "foo", - input_types: vec![InterfaceType::I32], - output_types: vec![], - instructions: vec![Instruction::CallExport { export_name: "f" }], - }) - .to_string(), - (&Adapter::Import { - namespace: "ns", - name: "foo", - input_types: vec![], - output_types: vec![InterfaceType::I32], - instructions: vec![Instruction::CallExport { export_name: "f" }], - }) - .to_string(), - (&Adapter::Export { - name: "foo", - input_types: vec![InterfaceType::I32, InterfaceType::F32], - output_types: vec![InterfaceType::I32], - instructions: vec![ - Instruction::ArgumentGet { index: 0 }, - Instruction::WriteUtf8 { - allocator_name: "hello", - }, - Instruction::CallExport { export_name: "f" }, - ], - }) - .to_string(), - (&Adapter::Export { - name: "foo", - input_types: vec![InterfaceType::I32], - output_types: vec![], - instructions: vec![Instruction::CallExport { export_name: "f" }], - }) - .to_string(), - (&Adapter::Export { - name: "foo", - input_types: vec![], - output_types: vec![InterfaceType::I32], - instructions: vec![Instruction::CallExport { export_name: "f" }], - }) - .to_string(), - ]; - let outputs = vec![ - r#"(@interface adapt (import "ns" "foo") - (param i32 f32) - (result i32) - arg.get 0 - write-utf8 "hello" - call-export "f")"#, - r#"(@interface adapt (import "ns" "foo") - (param i32) - call-export "f")"#, - r#"(@interface adapt (import "ns" "foo") - (result i32) - call-export "f")"#, - r#"(@interface adapt (export "foo") - (param i32 f32) - (result i32) - arg.get 0 - write-utf8 "hello" - call-export "f")"#, - r#"(@interface adapt (export "foo") - (param i32) - call-export "f")"#, - r#"(@interface adapt (export "foo") - (result i32) - call-export "f")"#, - ]; + fn test_adapter() { + let input = (&Adapter { + function_type: 0, + instructions: vec![Instruction::ArgumentGet { index: 42 }], + }) + .to_string(); + let output = r#"(@interface func (type 0) + arg.get 42)"#; - assert_eq!(inputs, outputs); + assert_eq!(input, output); } #[test] fn test_interfaces() { let input: String = (&Interfaces { - exports: vec![ - Export { - name: "foo", - input_types: vec![InterfaceType::I32], - output_types: vec![], - }, - Export { - name: "bar", - input_types: vec![], - output_types: vec![], - }, - ], - types: vec![], - imports: vec![ - Import { - namespace: "ns", - name: "foo", - input_types: vec![], - output_types: vec![InterfaceType::I32], - }, - Import { - namespace: "ns", - name: "bar", - input_types: vec![], - output_types: vec![], - }, - ], - adapters: vec![ - Adapter::Import { - namespace: "ns", - name: "foo", - input_types: vec![InterfaceType::I32], - output_types: vec![], - instructions: vec![Instruction::ArgumentGet { index: 42 }], - }, - Adapter::Export { - name: "bar", - input_types: vec![], - output_types: vec![], - instructions: vec![Instruction::ArgumentGet { index: 42 }], - }, - ], + types: vec![Type { + inputs: vec![InterfaceType::I32], + outputs: vec![InterfaceType::S8], + }], + imports: vec![Import { + namespace: "ns", + name: "foo", + signature_type: 0, + }], + adapters: vec![Adapter { + function_type: 0, + instructions: vec![Instruction::ArgumentGet { index: 42 }], + }], + exports: vec![Export { + name: "bar", + function_type: 0, + }], + implementations: vec![Implementation { + core_function_type: 0, + adapter_function_type: 1, + }], }) .to_string(); - let output = r#";; Interfaces - -;; Interface, Export foo -(@interface export "foo" - (param i32)) - -;; Interface, Export bar -(@interface export "bar") - -;; Interface, Import ns.foo -(@interface func $ns_foo (import "ns" "foo") - (result i32)) - -;; Interface, Import ns.bar -(@interface func $ns_bar (import "ns" "bar")) - -;; Interface, Adapter ns.foo -(@interface adapt (import "ns" "foo") + let output = r#";; Types +(@interface type (func (param i32) + (result s8))) + +;; Imports +(@interface import "ns" "foo" (func (type 0))) + +;; Adapters +(@interface func (type 0) arg.get 42) -;; Interface, Adapter bar -(@interface adapt (export "bar") - arg.get 42)"#; +;; Exports +(@interface export "bar" (func 0)) + +;; Implementations +(@interface implement (func 0) (func 1))"#; assert_eq!(input, output); } diff --git a/tests/binary.rs b/tests/binary.rs index 365d753..0e89173 100644 --- a/tests/binary.rs +++ b/tests/binary.rs @@ -6,28 +6,33 @@ use wasmer_interface_types::{ #[test] fn test_binary_encoding_decoding_roundtrip() { let original_ast = Interfaces { - exports: vec![Export { - name: "ab", - input_types: vec![InterfaceType::I32], - output_types: vec![InterfaceType::I32], - }], - types: vec![Type { - inputs: vec![InterfaceType::I32, InterfaceType::I32], - outputs: vec![InterfaceType::S32], - }], + types: vec![ + Type { + inputs: vec![], + outputs: vec![], + }, + Type { + inputs: vec![InterfaceType::I32, InterfaceType::I32], + outputs: vec![InterfaceType::S32], + }, + ], imports: vec![Import { namespace: "a", name: "b", - input_types: vec![InterfaceType::I32], - output_types: vec![InterfaceType::I64], + signature_type: 0, }], - adapters: vec![Adapter::Import { - namespace: "a", - name: "b", - input_types: vec![InterfaceType::I32], - output_types: vec![InterfaceType::I32], + adapters: vec![Adapter { + function_type: 0, instructions: vec![Instruction::ArgumentGet { index: 1 }], }], + exports: vec![Export { + name: "ab", + function_type: 1, + }], + implementations: vec![Implementation { + core_function_type: 0, + adapter_function_type: 0, + }], }; let mut binary = vec![];