diff --git a/CHANGELOG.md b/CHANGELOG.md index cfc896b1b..efc1e983e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## **[Unreleased]** +- [#1439](https://github.com/wasmerio/wasmer/pull/1439) Move `wasmer-interface-types` into its own repository + ## 0.17.0 - 2020-05-11 - [#1401](https://github.com/wasmerio/wasmer/pull/1401) Make breaking change to `RuntimeError`: `RuntimeError` is now more explicit about its possible error values allowing for better insight into why a call into Wasm failed. diff --git a/Cargo.toml b/Cargo.toml index f48d98569..735d36886 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,7 +60,6 @@ members = [ "lib/kernel-loader", "lib/kernel-net", "lib/wasi-experimental-io-devices", - "lib/interface-types", "examples/parallel", "examples/plugin-for-example", "examples/parallel-guest", diff --git a/Makefile b/Makefile index 09a14fcf7..d25640485 100644 --- a/Makefile +++ b/Makefile @@ -214,7 +214,6 @@ test-capi: test-capi-singlepass test-capi-cranelift test-capi-llvm test-capi-ems capi-test: test-capi test-rest: - cargo test --release -p wasmer-interface-types cargo test --release -p wasmer-runtime cargo test --release -p wasmer-runtime-core cargo test --release -p wasmer-wasi-experimental-io-devices @@ -274,7 +273,7 @@ check-nightly: check-kernel-net # TODO: We wanted `--workspace --exclude wasmer-runtime`, but can't due # to https://github.com/rust-lang/cargo/issues/6745 . -NOT_RUNTIME_CRATES = -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-interface-types +NOT_RUNTIME_CRATES = -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader RUNTIME_CHECK = cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features check: check-bench cargo check $(NOT_RUNTIME_CRATES) diff --git a/lib/interface-types/Cargo.toml b/lib/interface-types/Cargo.toml deleted file mode 100644 index 5705b7da3..000000000 --- a/lib/interface-types/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "wasmer-interface-types" -version = "0.17.0" -description = "WebAssembly Interface Types library for Wasmer" -license = "MIT" -authors = ["The Wasmer Engineering Team "] -repository = "https://github.com/wasmerio/wasmer" -edition = "2018" - -[dependencies] -nom = "5.1" -wast = "8.0" - -# `serde` is useful only to simplify the users' life. It is not -# required by WIT itself, is is used to cross the boundary between the -# host and WIT more easily, but it is not used inside Wasm. -serde = { version = "1.0", features = ["derive"], optional = true } - -[features] -default = ["serde"] diff --git a/lib/interface-types/README.md b/lib/interface-types/README.md deleted file mode 100644 index 9605470b7..000000000 --- a/lib/interface-types/README.md +++ /dev/null @@ -1,94 +0,0 @@ -

- - Wasmer logo - -

- -

- - Build Status - - - License - - - Join the Wasmer Community - - - Number of downloads from crates.io - - - Read our API documentation - -

- -# Wasmer Interface Types - -Wasmer is a standalone JIT WebAssembly runtime, aiming to be fully -compatible with WASI, Emscripten, Rust and Go. [Learn -more](https://github.com/wasmerio/wasmer). - -This crate is an implementation of [the living WebAssembly Interface -Types standard](https://github.com/WebAssembly/interface-types). - -## Encoders and decoders - -The `wasmer-interface-types` crate comes with an encoder and a decoder -for the WAT format, and the binary format, for the WebAssembly -Interface Types. An encoder writes an AST into another format, like -WAT or binary. A decoder reads an AST from another format, like WAT or -binary. - -## Instructions - -Very basically, WebAssembly Interface Types defines a [set of -instructions](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/working-notes/Instructions.md), -used by adapters to transform the data between WebAssembly core and -the outside world ([learn -mode](https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md)). - -Here is the instructions that are implemented by this crate: - -| Instruction | WAT encoder/decoder | Binary encoder/decoder | Interpreter | Comment | -|-|-|-|-|-| -| `arg.get` | ✅ | ✅ | ✅ | | -| `call-core` | ✅ | ✅ | ✅ | | -| `s8.from_i32` | ✅ | ✅ | ✅ | | -| `s8.from_i64` | ✅ | ✅ | ✅ | | -| `s16.from_i32` | ✅ | ✅ | ✅ | | -| `s16.from_i64` | ✅ | ✅ | ✅ | | -| `s32.from_i32` | ✅ | ✅ | ✅ | | -| `s32.from_i64` | ✅ | ✅ | ✅ | | -| `s64.from_i32` | ✅ | ✅ | ✅ | | -| `s64.from_i64` | ✅ | ✅ | ✅ | | -| `i32.from_s8` | ✅ | ✅ | ✅ | | -| `i32.from_s16` | ✅ | ✅ | ✅ | | -| `i32.from_s32` | ✅ | ✅ | ✅ | | -| `i32.from_s64` | ✅ | ✅ | ✅ | | -| `i64.from_s8` | ✅ | ✅ | ✅ | | -| `i64.from_s16` | ✅ | ✅ | ✅ | | -| `i64.from_s32` | ✅ | ✅ | ✅ | | -| `i64.from_s64` | ✅ | ✅ | ✅ | | -| `u8.from_i32` | ✅ | ✅ | ✅ | | -| `u8.from_i64` | ✅ | ✅ | ✅ | | -| `u16.from_i32` | ✅ | ✅ | ✅ | | -| `u16.from_i64` | ✅ | ✅ | ✅ | | -| `u32.from_i32` | ✅ | ✅ | ✅ | | -| `u32.from_i64` | ✅ | ✅ | ✅ | | -| `u64.from_i32` | ✅ | ✅ | ✅ | | -| `u64.from_i64` | ✅ | ✅ | ✅ | | -| `i32.from_u8` | ✅ | ✅ | ✅ | | -| `i32.from_u16` | ✅ | ✅ | ✅ | | -| `i32.from_u32` | ✅ | ✅ | ✅ | | -| `i32.from_u64` | ✅ | ✅ | ✅ | | -| `i64.from_u8` | ✅ | ✅ | ✅ | | -| `i64.from_u16` | ✅ | ✅ | ✅ | | -| `i64.from_u32` | ✅ | ✅ | ✅ | | -| `i64.from_u64` | ✅ | ✅ | ✅ | | -| `string.lift_memory` | ✅ | ✅ | ✅ | `#memidx` is not supported; `#encoding` is not supported but UTF-8 is assumed | -| `string.lower_memory` | ✅ | ✅ | ✅ | `#memidx` is not supported; `#encoding` is not supported but UTF-8 is assumed | -| `string.size` | ✅ | ✅ | ✅ | `#encoding` is not supported but UTF-8 is assumed | -| `record.lift` | ✅ | ✅ | ✅ | | -| `record.lower` | ✅ | ✅ | ✅ | | -| `call-adapter` | ❌ | ❌ | ❌ | | -| `defer-call-core` | ❌ | ❌ | ❌ | | diff --git a/lib/interface-types/src/ast.rs b/lib/interface-types/src/ast.rs deleted file mode 100644 index 42fc8502a..000000000 --- a/lib/interface-types/src/ast.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! Represents the WIT language as a tree. This is the central -//! representation of the language. - -use crate::{ - interpreter::Instruction, - types::{InterfaceType, RecordType}, -}; -use std::str; - -/// Represents the kind of type. -#[derive(PartialEq, Debug)] -pub enum TypeKind { - /// A function type. - Function, - - /// A record type. - Record, -} - -/// Represents a type. -#[derive(PartialEq, Debug)] -pub enum Type { - /// A function type, like: - /// - /// ```wasm,ignore - /// (@interface type (func (param i32 i32) (result string))) - /// ``` - Function { - /// Types for the parameters (`(param …)`). - inputs: Vec, - - /// Types for the results (`(result …)`). - outputs: Vec, - }, - - /// A record type, like: - /// - /// ```wasm,ignore - /// (@interface type (record string i32)) - /// ``` - Record(RecordType), -} - -/// Represents an imported function. -#[derive(PartialEq, Debug)] -pub struct Import<'input> { - /// The function namespace. - pub namespace: &'input str, - - /// The function name. - pub name: &'input str, - - /// The type signature. - pub signature_type: u32, -} - -/// Represents an exported function signature. -#[derive(PartialEq, Debug)] -pub struct Export<'input> { - /// The export name. - pub name: &'input str, - - /// The WIT function type being exported. - pub function_type: u32, -} - -/// Represents an adapter. -#[derive(PartialEq, Debug)] -pub struct Adapter { - /// The adapter function type. - pub function_type: u32, - - /// The instructions. - 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 { - /// A type. - Type, - - /// An imported function. - Import, - - /// An adapter. - Adapter, - - /// An exported function. - Export, - - /// An implementation. - Implementation, -} - -/// Represents a set of interfaces, i.e. it entirely describes a WIT -/// definition. -#[derive(PartialEq, Default, Debug)] -pub struct Interfaces<'input> { - /// All the types. - pub types: Vec, - - /// All the imported functions. - pub imports: Vec>, - - /// All the adapters. - pub adapters: Vec, - - /// All the exported functions. - pub exports: Vec>, - - /// All the implementations. - pub implementations: Vec, -} diff --git a/lib/interface-types/src/decoders/binary.rs b/lib/interface-types/src/decoders/binary.rs deleted file mode 100644 index ce0f11003..000000000 --- a/lib/interface-types/src/decoders/binary.rs +++ /dev/null @@ -1,990 +0,0 @@ -//! Parse the WIT binary representation into an [AST](crate::ast). - -use crate::{ast::*, interpreter::Instruction, types::*, vec1::Vec1}; -use nom::{ - error::{make_error, ErrorKind, ParseError}, - Err, IResult, -}; -use std::{convert::TryFrom, str}; - -/// Parse a type kind. -impl TryFrom for TypeKind { - type Error = &'static str; - - fn try_from(code: u8) -> Result { - Ok(match code { - 0x00 => Self::Function, - 0x01 => Self::Record, - _ => return Err("Unknown type kind code."), - }) - } -} - -/// Parse an interface kind. -impl TryFrom for InterfaceKind { - type Error = &'static str; - - fn try_from(code: u8) -> Result { - Ok(match code { - 0x00 => Self::Type, - 0x01 => Self::Import, - 0x02 => Self::Adapter, - 0x03 => Self::Export, - 0x04 => Self::Implementation, - _ => return Err("Unknown interface kind code."), - }) - } -} - -/// Parse a byte. -fn byte<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'input [u8], u8, E> { - if input.is_empty() { - return Err(Err::Error(make_error(input, ErrorKind::Eof))); - } - - Ok((&input[1..], input[0])) -} - -/// Parse an unsigned Little Endian Based (LEB) with value no larger -/// than a 64-bits number. Read -/// [LEB128](https://en.wikipedia.org/wiki/LEB128) to learn more, or -/// the Variable Length Data Section from the [DWARF 4 -/// standard](http://dwarfstd.org/doc/DWARF4.pdf). -fn uleb<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'input [u8], u64, E> { - if input.is_empty() { - return Err(Err::Error(make_error(input, ErrorKind::Eof))); - } - - let (output, bytes) = match input.iter().position(|&byte| byte & 0x80 == 0) { - Some(length) if length <= 8 => (&input[length + 1..], &input[..=length]), - Some(_) => return Err(Err::Error(make_error(input, ErrorKind::TooLarge))), - None => return Err(Err::Error(make_error(input, ErrorKind::Eof))), - }; - - Ok(( - output, - bytes - .iter() - .rev() - .fold(0, |acc, byte| (acc << 7) | u64::from(byte & 0x7f)), - )) -} - -/// 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 a 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: Vec1::new(fields).expect("Record must have at least one field, zero given."), - }, - )) -} - -/// Parse a UTF-8 string. -fn string<'input, E: ParseError<&'input [u8]>>( - input: &'input [u8], -) -> IResult<&'input [u8], &'input str, E> { - if input.is_empty() { - return Err(Err::Error(make_error(input, ErrorKind::Eof))); - } - - let length = input[0] as usize; - let input = &input[1..]; - - if input.len() < length { - return Err(Err::Error(make_error(input, ErrorKind::Eof))); - } - - Ok(( - &input[length..], - str::from_utf8(&input[..length]) - .map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?, - )) -} - -/// Parse a list, with an item parser. -#[allow(clippy::type_complexity)] -fn list<'input, I, E: ParseError<&'input [u8]>>( - input: &'input [u8], - item_parser: fn(&'input [u8]) -> IResult<&'input [u8], I, E>, -) -> IResult<&'input [u8], Vec, E> { - if input.is_empty() { - return Err(Err::Error(make_error(input, ErrorKind::Eof))); - } - - let length = input[0] as usize; - let mut input = &input[1..]; - - if input.len() < length { - return Err(Err::Error(make_error(input, ErrorKind::Eof))); - } - - let mut items = Vec::with_capacity(length as usize); - - for _ in 0..length { - consume!((input, item) = item_parser(input)?); - items.push(item); - } - - Ok((input, items)) -} - -/// Parse an instruction with its arguments. -fn instruction<'input, E: ParseError<&'input [u8]>>( - input: &'input [u8], -) -> IResult<&'input [u8], Instruction, E> { - let (mut input, opcode) = byte(input)?; - - Ok(match opcode { - 0x00 => { - consume!((input, argument_0) = uleb(input)?); - - ( - input, - Instruction::ArgumentGet { - index: argument_0 as u32, - }, - ) - } - - 0x01 => { - consume!((input, argument_0) = uleb(input)?); - - ( - input, - Instruction::CallCore { - function_index: argument_0 as u32, - }, - ) - } - - 0x02 => (input, Instruction::S8FromI32), - 0x03 => (input, Instruction::S8FromI64), - 0x04 => (input, Instruction::S16FromI32), - 0x05 => (input, Instruction::S16FromI64), - 0x06 => (input, Instruction::S32FromI32), - 0x07 => (input, Instruction::S32FromI64), - 0x08 => (input, Instruction::S64FromI32), - 0x09 => (input, Instruction::S64FromI64), - 0x0a => (input, Instruction::I32FromS8), - 0x0b => (input, Instruction::I32FromS16), - 0x0c => (input, Instruction::I32FromS32), - 0x0d => (input, Instruction::I32FromS64), - 0x0e => (input, Instruction::I64FromS8), - 0x0f => (input, Instruction::I64FromS16), - 0x10 => (input, Instruction::I64FromS32), - 0x11 => (input, Instruction::I64FromS64), - 0x12 => (input, Instruction::U8FromI32), - 0x13 => (input, Instruction::U8FromI64), - 0x14 => (input, Instruction::U16FromI32), - 0x15 => (input, Instruction::U16FromI64), - 0x16 => (input, Instruction::U32FromI32), - 0x17 => (input, Instruction::U32FromI64), - 0x18 => (input, Instruction::U64FromI32), - 0x19 => (input, Instruction::U64FromI64), - 0x1a => (input, Instruction::I32FromU8), - 0x1b => (input, Instruction::I32FromU16), - 0x1c => (input, Instruction::I32FromU32), - 0x1d => (input, Instruction::I32FromU64), - 0x1e => (input, Instruction::I64FromU8), - 0x1f => (input, Instruction::I64FromU16), - 0x20 => (input, Instruction::I64FromU32), - 0x21 => (input, Instruction::I64FromU64), - - 0x22 => (input, Instruction::StringLiftMemory), - 0x23 => (input, Instruction::StringLowerMemory), - 0x24 => (input, Instruction::StringSize), - - 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, - }, - ) - } - - _ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))), - }) -} - -/// Parse a list of types. -fn types<'input, E: ParseError<&'input [u8]>>( - mut input: &'input [u8], -) -> IResult<&'input [u8], Vec, E> { - consume!((input, number_of_types) = uleb(input)?); - - let mut types = Vec::with_capacity(number_of_types as usize); - - for _ in 0..number_of_types { - consume!((input, type_kind) = byte(input)?); - - let type_kind = TypeKind::try_from(type_kind) - .map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?; - - match type_kind { - TypeKind::Function => { - consume!((input, inputs) = list(input, ty)?); - consume!((input, outputs) = list(input, ty)?); - - types.push(Type::Function { inputs, outputs }); - } - - TypeKind::Record => { - consume!((input, record_type) = record_type(input)?); - - types.push(Type::Record(record_type)); - } - } - } - - Ok((input, types)) -} - -/// Parse a list of imports. -fn imports<'input, E: ParseError<&'input [u8]>>( - mut input: &'input [u8], -) -> IResult<&'input [u8], Vec, E> { - consume!((input, number_of_imports) = uleb(input)?); - - let mut imports = Vec::with_capacity(number_of_imports as usize); - - for _ in 0..number_of_imports { - consume!((input, namespace) = string(input)?); - consume!((input, name) = string(input)?); - consume!((input, signature_type) = uleb(input)?); - - imports.push(Import { - namespace, - name, - signature_type: signature_type as u32, - }); - } - - Ok((input, imports)) -} - -/// Parse a list of adapters. -fn adapters<'input, E: ParseError<&'input [u8]>>( - mut input: &'input [u8], -) -> IResult<&'input [u8], Vec, E> { - consume!((input, number_of_adapters) = uleb(input)?); - - let mut adapters = Vec::with_capacity(number_of_adapters as usize); - - for _ in 0..number_of_adapters { - consume!((input, function_type) = uleb(input)?); - consume!((input, instructions) = list(input, instruction)?); - - adapters.push(Adapter { - function_type: function_type as u32, - instructions, - }); - } - - Ok((input, adapters)) -} - -/// Parse a list of exports. -fn exports<'input, E: ParseError<&'input [u8]>>( - mut input: &'input [u8], -) -> IResult<&'input [u8], Vec, E> { - consume!((input, number_of_exports) = uleb(input)?); - - let mut exports = Vec::with_capacity(number_of_exports as usize); - - for _ in 0..number_of_exports { - consume!((input, name) = string(input)?); - consume!((input, function_type) = uleb(input)?); - - exports.push(Export { - name, - function_type: function_type as u32, - }); - } - - Ok((input, exports)) -} - -/// Parse a list of implementations. -fn implementations<'input, E: ParseError<&'input [u8]>>( - mut input: &'input [u8], -) -> IResult<&'input [u8], Vec, E> { - consume!((input, number_of_implementations) = uleb(input)?); - - let mut implementations = Vec::with_capacity(number_of_implementations as usize); - - for _ in 0..number_of_implementations { - consume!((input, core_function_type) = uleb(input)?); - consume!((input, adapter_function_type) = uleb(input)?); - - implementations.push(Implementation { - core_function_type: core_function_type as u32, - adapter_function_type: adapter_function_type as u32, - }); - } - - Ok((input, implementations)) -} - -/// Parse complete interfaces. -fn interfaces<'input, E: ParseError<&'input [u8]>>( - bytes: &'input [u8], -) -> IResult<&'input [u8], Interfaces, E> { - let mut input = bytes; - - 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![]; - - while !input.is_empty() { - consume!((input, interface_kind) = byte(input)?); - - let interface_kind = InterfaceKind::try_from(interface_kind) - .map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?; - - match interface_kind { - InterfaceKind::Type => { - consume!((input, mut new_types) = types(input)?); - all_types.append(&mut new_types); - } - - InterfaceKind::Import => { - consume!((input, mut new_imports) = imports(input)?); - all_imports.append(&mut new_imports); - } - - 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) - } - } - } - - Ok(( - input, - Interfaces { - types: all_types, - imports: all_imports, - adapters: all_adapters, - exports: all_exports, - implementations: all_implementations, - }, - )) -} - -/// Parse a sequence of bytes, expecting it to be a valid WIT binary -/// representation, into an [`Interfaces`](crate::ast::Interfaces) -/// structure. -/// -/// # Example -/// -/// ```rust -/// use wasmer_interface_types::{ -/// ast::{Adapter, Export, Implementation, Import, Interfaces, Type}, -/// decoders::binary::parse, -/// interpreter::Instruction, -/// types::InterfaceType, -/// }; -/// -/// let input = &[ -/// 0x00, // type section -/// 0x01, // 1 type -/// 0x00, // function 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, // function type -/// // -/// 0x04, // implementation section -/// 0x01, // 1 implementation -/// 0x02, // core function type -/// 0x03, // adapter function type -/// ]; -/// let output = Ok(( -/// &[] as &[u8], -/// Interfaces { -/// types: vec![Type::Function { -/// inputs: vec![InterfaceType::S8], -/// outputs: vec![InterfaceType::S16], -/// }], -/// imports: vec![Import { -/// namespace: "ab", -/// name: "c", -/// signature_type: 0, -/// }], -/// 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, -/// }], -/// }, -/// )); -/// -/// assert_eq!(parse::<()>(input), output); -/// ``` -pub fn parse<'input, E: ParseError<&'input [u8]>>( - bytes: &'input [u8], -) -> IResult<&'input [u8], Interfaces, E> { - interfaces(bytes) -} - -#[cfg(test)] -mod tests { - use super::*; - use nom::{error, Err}; - - #[test] - fn test_byte() { - let input = &[0x01, 0x02, 0x03]; - let output = Ok((&[0x02, 0x03][..], 0x01u8)); - - assert_eq!(byte::<()>(input), output); - } - - #[test] - fn test_uleb_1_byte() { - let input = &[0x01, 0x02, 0x03]; - let output = Ok((&[0x02, 0x03][..], 0x01u64)); - - assert_eq!(uleb::<()>(input), output); - } - - #[test] - fn test_uleb_3_bytes() { - let input = &[0xfc, 0xff, 0x01, 0x02]; - let output = Ok((&[0x02][..], 0x7ffcu64)); - - assert_eq!(uleb::<()>(input), output); - } - - // Examples from Figure 22 of [DWARF 4 - // standard](http://dwarfstd.org/doc/DWARF4.pdf). - #[test] - fn test_uleb_from_dwarf_standard() { - macro_rules! assert_uleb { - ($to_parse:expr => $expected_result:expr) => { - assert_eq!(uleb::<()>($to_parse), Ok((&[][..], $expected_result))); - }; - } - - assert_uleb!(&[2u8] => 2u64); - assert_uleb!(&[127u8] => 127u64); - assert_uleb!(&[0x80, 1u8] => 128u64); - assert_uleb!(&[1u8 | 0x80, 1] => 129u64); - assert_uleb!(&[2u8 | 0x80, 1] => 130u64); - assert_uleb!(&[57u8 | 0x80, 100] => 12857u64); - } - - #[test] - fn test_uleb_eof() { - let input = &[0x80]; - - assert_eq!( - uleb::<(&[u8], error::ErrorKind)>(input), - Err(Err::Error((&input[..], error::ErrorKind::Eof))), - ); - } - - #[test] - fn test_uleb_overflow() { - let input = &[ - 0x01 | 0x80, - 0x02 | 0x80, - 0x03 | 0x80, - 0x04 | 0x80, - 0x05 | 0x80, - 0x06 | 0x80, - 0x07 | 0x80, - 0x08 | 0x80, - 0x09 | 0x80, - 0x0a, - ]; - - assert_eq!( - uleb::<(&[u8], error::ErrorKind)>(input), - Err(Err::Error((&input[..], error::ErrorKind::TooLarge))), - ); - } - - #[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: vec1![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: vec1![InterfaceType::String], - }, - RecordType { - fields: vec1![InterfaceType::String, InterfaceType::I32], - }, - RecordType { - fields: vec1![ - InterfaceType::String, - InterfaceType::Record(RecordType { - fields: vec1![InterfaceType::I32, InterfaceType::I32], - }), - InterfaceType::F64, - ], - }, - ], - )); - - assert_eq!(list::<_, ()>(input, record_type), output); - } - - #[test] - fn test_string() { - let input = &[ - 0x03, // string of 3 bytes - 0x61, // "a" - 0x62, // "b" - 0x63, // "c" - 0x64, 0x65, - ]; - let output = Ok((&[0x64, 0x65][..], "abc")); - - assert_eq!(string::<()>(input), output); - } - - #[test] - fn test_list() { - let input = &[ - 0x02, // list of 2 items - 0x01, // string of 1 byte - 0x61, // "a" - 0x02, // string of 2 bytes - 0x62, // "b" - 0x63, // "c" - 0x07, - ]; - let output = Ok((&[0x07][..], vec!["a", "bc"])); - - assert_eq!(list::<_, ()>(input, string), output); - } - - #[test] - fn test_instructions() { - let input = &[ - 0x27, // list of 39 items - 0x00, 0x01, // ArgumentGet { index: 1 } - 0x01, 0x01, // CallCore { function_index: 1 } - 0x02, // S8FromI32 - 0x03, // S8FromI64 - 0x04, // S16FromI32 - 0x05, // S16FromI64 - 0x06, // S32FromI32 - 0x07, // S32FromI64 - 0x08, // S64FromI32 - 0x09, // S64FromI64 - 0x0a, // I32FromS8 - 0x0b, // I32FromS16 - 0x0c, // I32FromS32 - 0x0d, // I32FromS64 - 0x0e, // I64FromS8 - 0x0f, // I64FromS16 - 0x10, // I64FromS32 - 0x11, // I64FromS64 - 0x12, // U8FromI32 - 0x13, // U8FromI64 - 0x14, // U16FromI32 - 0x15, // U16FromI64 - 0x16, // U32FromI32 - 0x17, // U32FromI64 - 0x18, // U64FromI32 - 0x19, // U64FromI64 - 0x1a, // I32FromU8 - 0x1b, // I32FromU16 - 0x1c, // I32FromU32 - 0x1d, // I32FromU64 - 0x1e, // I64FromU8 - 0x1f, // I64FromU16 - 0x20, // I64FromU32 - 0x21, // I64FromU64 - 0x22, // StringLiftMemory - 0x23, // StringLowerMemory - 0x24, // StringSize - 0x25, 0x01, // RecordLift { type_index: 1 }, - 0x26, 0x01, // RecordLower { type_index: 1 }, - 0x0a, - ]; - let output = Ok(( - &[0x0a][..], - vec![ - Instruction::ArgumentGet { index: 1 }, - Instruction::CallCore { function_index: 1 }, - Instruction::S8FromI32, - Instruction::S8FromI64, - Instruction::S16FromI32, - Instruction::S16FromI64, - Instruction::S32FromI32, - Instruction::S32FromI64, - Instruction::S64FromI32, - Instruction::S64FromI64, - Instruction::I32FromS8, - Instruction::I32FromS16, - Instruction::I32FromS32, - Instruction::I32FromS64, - Instruction::I64FromS8, - Instruction::I64FromS16, - Instruction::I64FromS32, - Instruction::I64FromS64, - Instruction::U8FromI32, - Instruction::U8FromI64, - Instruction::U16FromI32, - Instruction::U16FromI64, - Instruction::U32FromI32, - Instruction::U32FromI64, - Instruction::U64FromI32, - Instruction::U64FromI64, - Instruction::I32FromU8, - Instruction::I32FromU16, - Instruction::I32FromU32, - Instruction::I32FromU64, - Instruction::I64FromU8, - Instruction::I64FromU16, - Instruction::I64FromU32, - Instruction::I64FromU64, - Instruction::StringLiftMemory, - Instruction::StringLowerMemory, - Instruction::StringSize, - Instruction::RecordLift { type_index: 1 }, - Instruction::RecordLower { type_index: 1 }, - ], - )); - - assert_eq!(list::<_, ()>(input, instruction), output); - } - - #[test] - fn test_exports() { - let input = &[ - 0x02, // 2 exports - 0x02, // string of 2 bytes - 0x61, 0x62, // "a", "b" - 0x01, // function type - 0x02, // string of 2 bytes - 0x63, 0x64, // "c", "d" - 0x02, // function type - ]; - let output = Ok(( - &[] as &[u8], - vec![ - Export { - name: "ab", - function_type: 1, - }, - Export { - name: "cd", - function_type: 2, - }, - ], - )); - - assert_eq!(exports::<()>(input), output); - } - - #[test] - fn test_types() { - let input = &[ - 0x02, // 2 type - 0x00, // function type - 0x02, // list of 2 items - 0x02, // S32 - 0x02, // S32 - 0x01, // list of 2 items - 0x02, // S32 - 0x01, // record type - 0x02, // list of 2 items - 0x02, // S32 - 0x02, // S32 - ]; - let output = Ok(( - &[] as &[u8], - vec![ - Type::Function { - inputs: vec![InterfaceType::S32, InterfaceType::S32], - outputs: vec![InterfaceType::S32], - }, - Type::Record(RecordType { - fields: vec1![InterfaceType::S32, InterfaceType::S32], - }), - ], - )); - - assert_eq!(types::<()>(input), output); - } - - #[test] - fn test_imports() { - let input = &[ - 0x02, // 2 imports - 0x01, // string of 1 byte - 0x61, // "a" - 0x01, // string of 1 byte - 0x62, // "b" - 0x01, // signature type - 0x01, // string of 1 byte - 0x63, // "c" - 0x01, // string of 1 byte - 0x64, // "d" - 0x02, // signature type - ]; - let output = Ok(( - &[] as &[u8], - vec![ - Import { - namespace: "a", - name: "b", - signature_type: 1, - }, - Import { - namespace: "c", - name: "d", - signature_type: 2, - }, - ], - )); - - assert_eq!(imports::<()>(input), output); - } - - #[test] - fn test_adapters() { - let input = &[ - 0x01, // 1 adapters - 0x00, // function type - 0x01, // list of 1 item - 0x00, 0x01, // ArgumentGet { index: 1 } - ]; - let output = Ok(( - &[] as &[u8], - vec![Adapter { - function_type: 0, - instructions: vec![Instruction::ArgumentGet { index: 1 }], - }], - )); - - assert_eq!(adapters::<()>(input), output); - } - - #[test] - fn test_parse() { - let input = &[ - 0x00, // type section - 0x01, // 1 type - 0x00, // function 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, // function type - // - 0x04, // implementation section - 0x01, // 1 implementation - 0x02, // core function type - 0x03, // adapter function type - ]; - let output = Ok(( - &[] as &[u8], - Interfaces { - types: vec![Type::Function { - inputs: vec![InterfaceType::S8], - outputs: vec![InterfaceType::S16], - }], - imports: vec![Import { - namespace: "ab", - name: "c", - signature_type: 0, - }], - 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, - }], - }, - )); - - assert_eq!(interfaces::<()>(input), output); - } -} diff --git a/lib/interface-types/src/decoders/mod.rs b/lib/interface-types/src/decoders/mod.rs deleted file mode 100644 index 399bb896e..000000000 --- a/lib/interface-types/src/decoders/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Reads the AST from a particular data representation; for instance, -//! [`decoders::binary`](binary) reads the [AST](crate::ast) -//! from a binary. - -pub mod binary; -pub mod wat; diff --git a/lib/interface-types/src/decoders/wat.rs b/lib/interface-types/src/decoders/wat.rs deleted file mode 100644 index eb2f244b0..000000000 --- a/lib/interface-types/src/decoders/wat.rs +++ /dev/null @@ -1,977 +0,0 @@ -//! Parse the WIT textual representation into an [AST](crate::ast). - -use crate::{ast::*, interpreter::Instruction, types::*, vec1::Vec1}; -pub use wast::parser::ParseBuffer as Buffer; -use wast::parser::{self, Cursor, Parse, Parser, Peek, Result}; - -mod keyword { - pub use wast::{ - custom_keyword, - kw::{anyref, export, f32, f64, func, i32, i64, import, param, result}, - }; - - // New keywords. - custom_keyword!(implement); - custom_keyword!(r#type = "type"); - custom_keyword!(record); - custom_keyword!(field); - - // New types. - custom_keyword!(s8); - custom_keyword!(s16); - custom_keyword!(s32); - custom_keyword!(s64); - custom_keyword!(u8); - custom_keyword!(u16); - custom_keyword!(u32); - custom_keyword!(u64); - custom_keyword!(string); - - // Instructions. - custom_keyword!(argument_get = "arg.get"); - custom_keyword!(call_core = "call-core"); - custom_keyword!(s8_from_i32 = "s8.from_i32"); - custom_keyword!(s8_from_i64 = "s8.from_i64"); - custom_keyword!(s16_from_i32 = "s16.from_i32"); - custom_keyword!(s16_from_i64 = "s16.from_i64"); - custom_keyword!(s32_from_i32 = "s32.from_i32"); - custom_keyword!(s32_from_i64 = "s32.from_i64"); - custom_keyword!(s64_from_i32 = "s64.from_i32"); - custom_keyword!(s64_from_i64 = "s64.from_i64"); - custom_keyword!(i32_from_s8 = "i32.from_s8"); - custom_keyword!(i32_from_s16 = "i32.from_s16"); - custom_keyword!(i32_from_s32 = "i32.from_s32"); - custom_keyword!(i32_from_s64 = "i32.from_s64"); - custom_keyword!(i64_from_s8 = "i64.from_s8"); - custom_keyword!(i64_from_s16 = "i64.from_s16"); - custom_keyword!(i64_from_s32 = "i64.from_s32"); - custom_keyword!(i64_from_s64 = "i64.from_s64"); - custom_keyword!(u8_from_i32 = "u8.from_i32"); - custom_keyword!(u8_from_i64 = "u8.from_i64"); - custom_keyword!(u16_from_i32 = "u16.from_i32"); - custom_keyword!(u16_from_i64 = "u16.from_i64"); - custom_keyword!(u32_from_i32 = "u32.from_i32"); - custom_keyword!(u32_from_i64 = "u32.from_i64"); - custom_keyword!(u64_from_i32 = "u64.from_i32"); - custom_keyword!(u64_from_i64 = "u64.from_i64"); - custom_keyword!(i32_from_u8 = "i32.from_u8"); - custom_keyword!(i32_from_u16 = "i32.from_u16"); - custom_keyword!(i32_from_u32 = "i32.from_u32"); - custom_keyword!(i32_from_u64 = "i32.from_u64"); - custom_keyword!(i64_from_u8 = "i64.from_u8"); - custom_keyword!(i64_from_u16 = "i64.from_u16"); - custom_keyword!(i64_from_u32 = "i64.from_u32"); - custom_keyword!(i64_from_u64 = "i64.from_u64"); - custom_keyword!(string_lift_memory = "string.lift_memory"); - custom_keyword!(string_lower_memory = "string.lower_memory"); - custom_keyword!(string_size = "string.size"); - custom_keyword!(record_lift = "record.lift"); - custom_keyword!(record_lower = "record.lower"); -} - -impl Parse<'_> for InterfaceType { - fn parse(parser: Parser<'_>) -> Result { - let mut lookahead = parser.lookahead1(); - - if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::S8) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::S16) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::S32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::S64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::U8) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::U16) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::U32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::U64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::F32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::F64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::String) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::Anyref) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::I32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(InterfaceType::I64) - } else if lookahead.peek::() { - Ok(InterfaceType::Record(parser.parse()?)) - } else { - Err(lookahead.error()) - } - } -} - -impl Parse<'_> for RecordType { - fn parse(parser: Parser<'_>) -> Result { - parser.parse::()?; - - let mut fields = vec![]; - - while !parser.is_empty() { - fields.push(parser.parens(|parser| { - parser.parse::()?; - - parser.parse() - })?); - } - - Ok(RecordType { - fields: Vec1::new(fields).expect("Record must have at least one field, zero given."), - }) - } -} - -impl<'a> Parse<'a> for Instruction { - #[allow(clippy::cognitive_complexity)] - fn parse(parser: Parser<'a>) -> Result { - let mut lookahead = parser.lookahead1(); - - if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::ArgumentGet { - index: parser.parse()?, - }) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::CallCore { - function_index: parser.parse::()?, - }) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S8FromI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S8FromI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S16FromI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S16FromI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S32FromI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S32FromI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S64FromI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::S64FromI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32FromS8) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32FromS16) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32FromS32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32FromS64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64FromS8) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64FromS16) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64FromS32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64FromS64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U8FromI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U8FromI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U16FromI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U16FromI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U32FromI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U32FromI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U64FromI32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::U64FromI64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32FromU8) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32FromU16) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32FromU32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I32FromU64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64FromU8) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64FromU16) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64FromU32) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::I64FromU64) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::StringLiftMemory) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::StringLowerMemory) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::StringSize) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::RecordLift { - type_index: parser.parse()?, - }) - } else if lookahead.peek::() { - parser.parse::()?; - - Ok(Instruction::RecordLower { - type_index: parser.parse()?, - }) - } else { - Err(lookahead.error()) - } - } -} - -struct AtInterface; - -impl Peek for AtInterface { - fn peek(cursor: Cursor<'_>) -> bool { - cursor.reserved().map(|(string, _)| string) == Some("@interface") - } - - fn display() -> &'static str { - "`@interface`" - } -} - -impl Parse<'_> for AtInterface { - fn parse(parser: Parser<'_>) -> Result { - parser.step(|cursor| { - if let Some(("@interface", rest)) = cursor.reserved() { - return Ok((AtInterface, rest)); - } - - Err(cursor.error("expected `@interface`")) - }) - } -} - -#[derive(PartialEq, Debug)] -enum FunctionType { - Input(Vec), - Output(Vec), -} - -impl Parse<'_> for FunctionType { - fn parse(parser: Parser<'_>) -> Result { - parser.parens(|parser| { - let mut lookahead = parser.lookahead1(); - - if lookahead.peek::() { - parser.parse::()?; - - let mut inputs = vec![]; - - while !parser.is_empty() { - inputs.push(parser.parse()?); - } - - Ok(FunctionType::Input(inputs)) - } else if lookahead.peek::() { - parser.parse::()?; - - let mut outputs = vec![]; - - while !parser.is_empty() { - outputs.push(parser.parse()?); - } - - Ok(FunctionType::Output(outputs)) - } else { - Err(lookahead.error()) - } - }) - } -} - -#[derive(PartialEq, Debug)] -enum Interface<'a> { - Type(Type), - Import(Import<'a>), - Adapter(Adapter), - Export(Export<'a>), - Implementation(Implementation), -} - -impl<'a> Parse<'a> for Interface<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parens(|parser| { - let mut lookahead = parser.lookahead1(); - - if lookahead.peek::() { - parser.parse::()?; - - let mut lookahead = parser.lookahead1(); - - if lookahead.peek::() { - Ok(Interface::Type(parser.parse()?)) - } else if lookahead.peek::() { - Ok(Interface::Import(parser.parse()?)) - } else if lookahead.peek::() { - Ok(Interface::Adapter(parser.parse()?)) - } else if lookahead.peek::() { - Ok(Interface::Export(parser.parse()?)) - } else if lookahead.peek::() { - Ok(Interface::Implementation(parser.parse()?)) - } else { - Err(lookahead.error()) - } - } else { - Err(lookahead.error()) - } - }) - } -} - -impl<'a> Parse<'a> for Type { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - - let ty = parser.parens(|parser| { - let mut lookahead = parser.lookahead1(); - - if lookahead.peek::() { - parser.parse::()?; - - let mut input_types = vec![]; - let mut output_types = vec![]; - - while !parser.is_empty() { - let function_type = parser.parse::()?; - - match function_type { - FunctionType::Input(mut inputs) => input_types.append(&mut inputs), - FunctionType::Output(mut outputs) => output_types.append(&mut outputs), - } - } - - Ok(Type::Function { - inputs: input_types, - outputs: output_types, - }) - } else if lookahead.peek::() { - Ok(Type::Record(parser.parse()?)) - } else { - Err(lookahead.error()) - } - })?; - - Ok(ty) - } -} - -impl<'a> Parse<'a> for Import<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - - let namespace = parser.parse()?; - let name = parser.parse()?; - - let signature_type = parser.parens(|parser| { - parser.parse::()?; - - parser.parens(|parser| { - parser.parse::()?; - - parser.parse() - }) - })?; - - Ok(Import { - namespace, - name, - signature_type, - }) - } -} - -impl<'a> Parse<'a> for Export<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - - let name = parser.parse()?; - - let function_type = parser.parens(|parser| { - parser.parse::()?; - - parser.parse() - })?; - - Ok(Export { - name, - function_type, - }) - } -} - -impl<'a> Parse<'a> for Implementation { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - - let core_function_type = parser.parens(|parser| { - parser.parse::()?; - - parser.parse() - })?; - - let adapter_function_type = parser.parens(|parser| { - parser.parse::()?; - - parser.parse() - })?; - - Ok(Implementation { - core_function_type, - adapter_function_type, - }) - } -} - -impl<'a> Parse<'a> for Adapter { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - - let function_type = parser.parens(|parser| { - parser.parse::()?; - - parser.parse() - })?; - - let mut instructions = vec![]; - - while !parser.is_empty() { - instructions.push(parser.parse()?); - } - - Ok(Adapter { - function_type, - instructions, - }) - } -} - -impl<'a> Parse<'a> for Interfaces<'a> { - fn parse(parser: Parser<'a>) -> Result { - let mut interfaces: Interfaces = Default::default(); - - while !parser.is_empty() { - let interface = parser.parse::()?; - - match interface { - Interface::Type(ty) => interfaces.types.push(ty), - Interface::Import(import) => interfaces.imports.push(import), - Interface::Adapter(adapter) => interfaces.adapters.push(adapter), - Interface::Export(export) => interfaces.exports.push(export), - Interface::Implementation(implementation) => { - interfaces.implementations.push(implementation) - } - } - } - - Ok(interfaces) - } -} - -/// Parse a WIT definition in its textual format, and produces an -/// [AST](crate::ast) with the [`Interfaces`](crate::ast::Interfaces) -/// structure upon succesful. -/// -/// # Examples -/// -/// ```rust -/// use wasmer_interface_types::{ -/// ast::{Adapter, Export, Implementation, Import, Interfaces, Type}, -/// decoders::wat::{parse, Buffer}, -/// interpreter::Instruction, -/// types::InterfaceType, -/// }; -/// -/// let input = Buffer::new( -/// r#"(@interface type (func (param i32) (result s8))) -/// -/// (@interface import "ns" "foo" (func (type 0))) -/// -/// (@interface func (type 0) arg.get 42) -/// -/// (@interface export "bar" (func 0)) -/// -/// (@interface implement (func 0) (func 1))"#, -/// ) -/// .unwrap(); -/// let output = Interfaces { -/// types: vec![Type::Function { -/// 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); -/// ``` -pub fn parse<'input>(input: &'input Buffer) -> Result> { - parser::parse::(&input) -} - -#[cfg(test)] -mod tests { - use super::*; - use wast::parser; - - fn buffer(input: &str) -> Buffer { - Buffer::new(input).expect("Failed to build the parser buffer.") - } - - #[test] - fn test_interface_type() { - let inputs = vec![ - "s8", - "s16", - "s32", - "s64", - "u8", - "u16", - "u32", - "u64", - "f32", - "f64", - "string", - "anyref", - "i32", - "i64", - "record (field string)", - ]; - let outputs = 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: vec1![InterfaceType::String], - }), - ]; - - assert_eq!(inputs.len(), outputs.len()); - - for (input, output) in inputs.iter().zip(outputs.iter()) { - assert_eq!( - &parser::parse::(&buffer(input)).unwrap(), - output - ); - } - } - - #[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: vec1![InterfaceType::String], - }, - RecordType { - fields: vec1![InterfaceType::String, InterfaceType::I32], - }, - RecordType { - fields: vec1![ - InterfaceType::String, - InterfaceType::Record(RecordType { - fields: vec1![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::(&buffer(input)).unwrap(), - output - ); - } - } - - #[test] - fn test_instructions() { - let inputs = vec![ - "arg.get 7", - "call-core 7", - "s8.from_i32", - "s8.from_i64", - "s16.from_i32", - "s16.from_i64", - "s32.from_i32", - "s32.from_i64", - "s64.from_i32", - "s64.from_i64", - "i32.from_s8", - "i32.from_s16", - "i32.from_s32", - "i32.from_s64", - "i64.from_s8", - "i64.from_s16", - "i64.from_s32", - "i64.from_s64", - "u8.from_i32", - "u8.from_i64", - "u16.from_i32", - "u16.from_i64", - "u32.from_i32", - "u32.from_i64", - "u64.from_i32", - "u64.from_i64", - "i32.from_u8", - "i32.from_u16", - "i32.from_u32", - "i32.from_u64", - "i64.from_u8", - "i64.from_u16", - "i64.from_u32", - "i64.from_u64", - "string.lift_memory", - "string.lower_memory", - "string.size", - "record.lift 42", - "record.lower 42", - ]; - let outputs = vec![ - Instruction::ArgumentGet { index: 7 }, - Instruction::CallCore { function_index: 7 }, - Instruction::S8FromI32, - Instruction::S8FromI64, - Instruction::S16FromI32, - Instruction::S16FromI64, - Instruction::S32FromI32, - Instruction::S32FromI64, - Instruction::S64FromI32, - Instruction::S64FromI64, - Instruction::I32FromS8, - Instruction::I32FromS16, - Instruction::I32FromS32, - Instruction::I32FromS64, - Instruction::I64FromS8, - Instruction::I64FromS16, - Instruction::I64FromS32, - Instruction::I64FromS64, - Instruction::U8FromI32, - Instruction::U8FromI64, - Instruction::U16FromI32, - Instruction::U16FromI64, - Instruction::U32FromI32, - Instruction::U32FromI64, - Instruction::U64FromI32, - Instruction::U64FromI64, - Instruction::I32FromU8, - Instruction::I32FromU16, - Instruction::I32FromU32, - Instruction::I32FromU64, - Instruction::I64FromU8, - Instruction::I64FromU16, - Instruction::I64FromU32, - Instruction::I64FromU64, - Instruction::StringLiftMemory, - Instruction::StringLowerMemory, - Instruction::StringSize, - Instruction::RecordLift { type_index: 42 }, - Instruction::RecordLower { type_index: 42 }, - ]; - - assert_eq!(inputs.len(), outputs.len()); - - for (input, output) in inputs.iter().zip(outputs.iter()) { - assert_eq!( - &parser::parse::(&buffer(input)).unwrap(), - output - ); - } - } - - #[test] - fn test_param_empty() { - let input = buffer("(param)"); - let output = FunctionType::Input(vec![]); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_param() { - let input = buffer("(param i32 string)"); - let output = FunctionType::Input(vec![InterfaceType::I32, InterfaceType::String]); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_result_empty() { - let input = buffer("(result)"); - let output = FunctionType::Output(vec![]); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_result() { - let input = buffer("(result i32 string)"); - let output = FunctionType::Output(vec![InterfaceType::I32, InterfaceType::String]); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_type_function() { - let input = buffer(r#"(@interface type (func (param i32 i32) (result i32)))"#); - let output = Interface::Type(Type::Function { - inputs: vec![InterfaceType::I32, InterfaceType::I32], - outputs: vec![InterfaceType::I32], - }); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_type_record() { - let input = buffer(r#"(@interface type (record (field string) (field i32)))"#); - let output = Interface::Type(Type::Record(RecordType { - fields: vec1![InterfaceType::String, InterfaceType::I32], - })); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_export() { - let input = buffer(r#"(@interface export "foo" (func 0))"#); - let output = Interface::Export(Export { - name: "foo", - function_type: 0, - }); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_export_escaped_name() { - let input = buffer(r#"(@interface export "fo\"o" (func 0))"#); - let output = Interface::Export(Export { - name: r#"fo"o"#, - function_type: 0, - }); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - fn test_import() { - let input = buffer(r#"(@interface import "ns" "foo" (func (type 0)))"#); - let output = Interface::Import(Import { - namespace: "ns", - name: "foo", - signature_type: 0, - }); - - assert_eq!(parser::parse::(&input).unwrap(), output); - } - - #[test] - 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_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); - } - - #[test] - fn test_interfaces() { - let input = buffer( - r#"(@interface type (func (param i32) (result s8))) - -(@interface import "ns" "foo" (func (type 0))) - -(@interface func (type 0) arg.get 42) - -(@interface export "bar" (func 0)) - -(@interface implement (func 0) (func 1))"#, - ); - let output = Interfaces { - types: vec![Type::Function { - 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/lib/interface-types/src/encoders/binary.rs b/lib/interface-types/src/encoders/binary.rs deleted file mode 100644 index dd2d072ed..000000000 --- a/lib/interface-types/src/encoders/binary.rs +++ /dev/null @@ -1,737 +0,0 @@ -//! Writes the AST into bytes representing WIT with its binary format. - -use crate::{ast::*, interpreter::Instruction, types::*}; -use std::io::{self, Write}; - -/// A trait for converting a value to bytes. -pub trait ToBytes -where - W: Write, -{ - /// Converts the given value into `&[u8]` in the given `writer`. - fn to_bytes(&self, writer: &mut W) -> io::Result<()>; -} - -/// Encode a `u8` into a byte (well, it's already a byte!). -impl ToBytes for u8 -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&[*self]) - } -} - -/// Encode a `u64` into bytes with a LEB128 representation. -/// -/// Decoder is `decoders::binary::uleb`. -impl ToBytes for u64 -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - let mut value = *self; - - // Code adapted from the Rust' `serialize` library. - loop { - if value < 0x80 { - writer.write_all(&[value as u8])?; - - break; - } - - writer.write_all(&[((value & 0x7f) | 0x80) as u8])?; - value >>= 7; - } - - Ok(()) - } -} - -/// Encode a `str` into bytes. -/// -/// Decoder is `decoders::binary::string`. -impl ToBytes for &str -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - // Size first. - writer.write_all(&[self.len() as u8])?; - - // Then the string. - writer.write_all(self.as_bytes())?; - - Ok(()) - } -} - -/// Encode a vector into bytes. -/// -/// Decoder is `decoders::binary::list`. -impl ToBytes for Vec -where - W: Write, - I: ToBytes, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - // Size first. - (self.len() as u64).to_bytes(writer)?; - - // Then the items. - for item in self { - item.to_bytes(writer)?; - } - - Ok(()) - } -} - -/// Encode an `InterfaceType` into bytes. -impl ToBytes for InterfaceType -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - match self { - InterfaceType::S8 => 0x00_u8.to_bytes(writer), - InterfaceType::S16 => 0x01_u8.to_bytes(writer), - InterfaceType::S32 => 0x02_u8.to_bytes(writer), - InterfaceType::S64 => 0x03_u8.to_bytes(writer), - InterfaceType::U8 => 0x04_u8.to_bytes(writer), - InterfaceType::U16 => 0x05_u8.to_bytes(writer), - InterfaceType::U32 => 0x06_u8.to_bytes(writer), - InterfaceType::U64 => 0x07_u8.to_bytes(writer), - InterfaceType::F32 => 0x08_u8.to_bytes(writer), - InterfaceType::F64 => 0x09_u8.to_bytes(writer), - InterfaceType::String => 0x0a_u8.to_bytes(writer), - 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) => { - 0x0e_u8.to_bytes(writer)?; - record_type.to_bytes(writer) - } - } - } -} - -/// Encode a `RecordType` into bytes. -impl ToBytes for RecordType -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - self.fields.to_bytes(writer) - } -} - -/// Encode a `TypeKind` into bytes. -impl ToBytes for TypeKind -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - match self { - TypeKind::Function => 0x00_u8.to_bytes(writer), - TypeKind::Record => 0x01_u8.to_bytes(writer), - } - } -} - -/// Encode an `InterfaceKind` into bytes. -impl ToBytes for InterfaceKind -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - match self { - Self::Type => 0x00_u8.to_bytes(writer), - Self::Import => 0x01_u8.to_bytes(writer), - Self::Adapter => 0x02_u8.to_bytes(writer), - Self::Export => 0x03_u8.to_bytes(writer), - Self::Implementation => 0x04_u8.to_bytes(writer), - } - } -} - -/// Encode a `Type` into bytes. -/// -/// Decoder is in `decoders::binary::types`. -impl ToBytes for Type -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - match self { - Type::Function { inputs, outputs } => { - TypeKind::Function.to_bytes(writer)?; - inputs.to_bytes(writer)?; - outputs.to_bytes(writer)?; - } - - Type::Record(record_type) => { - TypeKind::Record.to_bytes(writer)?; - record_type.to_bytes(writer)?; - } - } - - Ok(()) - } -} - -/// Encode an `Import` into bytes. -/// -/// Decoder is in `decoders::binary::imports`. -impl ToBytes for Import<'_> -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - self.namespace.to_bytes(writer)?; - self.name.to_bytes(writer)?; - (self.signature_type as u64).to_bytes(writer)?; - - Ok(()) - } -} - -/// Encode an `Adapter` into bytes. -/// -/// Decoder is in `decoders::binary::adapters`. -impl ToBytes for Adapter -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - (self.function_type as u64).to_bytes(writer)?; - self.instructions.to_bytes(writer)?; - - Ok(()) - } -} - -/// Encode an `Export` into bytes. -/// -/// Decoder is in `decoders::binary::exports`. -impl ToBytes for Export<'_> -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - self.name.to_bytes(writer)?; - (self.function_type as u64).to_bytes(writer)?; - - Ok(()) - } -} - -/// Encode an `Implementation` into bytes. -/// -/// Decoder is in `decoders::binary::implementations`. -impl ToBytes for Implementation -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - (self.core_function_type as u64).to_bytes(writer)?; - (self.adapter_function_type as u64).to_bytes(writer)?; - - Ok(()) - } -} - -/// Encode an `Interfaces` into bytes. -/// -/// Decoder is `decoders::binary::parse`. -impl ToBytes for Interfaces<'_> -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - if !self.types.is_empty() { - InterfaceKind::Type.to_bytes(writer)?; - self.types.to_bytes(writer)?; - } - - if !self.imports.is_empty() { - InterfaceKind::Import.to_bytes(writer)?; - self.imports.to_bytes(writer)?; - } - - if !self.adapters.is_empty() { - InterfaceKind::Adapter.to_bytes(writer)?; - self.adapters.to_bytes(writer)?; - } - - if !self.exports.is_empty() { - InterfaceKind::Export.to_bytes(writer)?; - self.exports.to_bytes(writer)?; - } - - if !self.implementations.is_empty() { - InterfaceKind::Implementation.to_bytes(writer)?; - self.implementations.to_bytes(writer)?; - } - - Ok(()) - } -} - -/// Encode an `Instruction` into bytes. -/// -/// Decoder is `decoders::binary::instruction`. -impl ToBytes for Instruction -where - W: Write, -{ - fn to_bytes(&self, writer: &mut W) -> io::Result<()> { - match self { - Instruction::ArgumentGet { index } => { - 0x00_u8.to_bytes(writer)?; - (*index as u64).to_bytes(writer)?; - } - - Instruction::CallCore { function_index } => { - 0x01_u8.to_bytes(writer)?; - (*function_index as u64).to_bytes(writer)?; - } - - Instruction::S8FromI32 => 0x02_u8.to_bytes(writer)?, - Instruction::S8FromI64 => 0x03_u8.to_bytes(writer)?, - Instruction::S16FromI32 => 0x04_u8.to_bytes(writer)?, - Instruction::S16FromI64 => 0x05_u8.to_bytes(writer)?, - Instruction::S32FromI32 => 0x06_u8.to_bytes(writer)?, - Instruction::S32FromI64 => 0x07_u8.to_bytes(writer)?, - Instruction::S64FromI32 => 0x08_u8.to_bytes(writer)?, - Instruction::S64FromI64 => 0x09_u8.to_bytes(writer)?, - Instruction::I32FromS8 => 0x0a_u8.to_bytes(writer)?, - Instruction::I32FromS16 => 0x0b_u8.to_bytes(writer)?, - Instruction::I32FromS32 => 0x0c_u8.to_bytes(writer)?, - Instruction::I32FromS64 => 0x0d_u8.to_bytes(writer)?, - Instruction::I64FromS8 => 0x0e_u8.to_bytes(writer)?, - Instruction::I64FromS16 => 0x0f_u8.to_bytes(writer)?, - Instruction::I64FromS32 => 0x10_u8.to_bytes(writer)?, - Instruction::I64FromS64 => 0x11_u8.to_bytes(writer)?, - Instruction::U8FromI32 => 0x12_u8.to_bytes(writer)?, - Instruction::U8FromI64 => 0x13_u8.to_bytes(writer)?, - Instruction::U16FromI32 => 0x14_u8.to_bytes(writer)?, - Instruction::U16FromI64 => 0x15_u8.to_bytes(writer)?, - Instruction::U32FromI32 => 0x16_u8.to_bytes(writer)?, - Instruction::U32FromI64 => 0x17_u8.to_bytes(writer)?, - Instruction::U64FromI32 => 0x18_u8.to_bytes(writer)?, - Instruction::U64FromI64 => 0x19_u8.to_bytes(writer)?, - Instruction::I32FromU8 => 0x1a_u8.to_bytes(writer)?, - Instruction::I32FromU16 => 0x1b_u8.to_bytes(writer)?, - Instruction::I32FromU32 => 0x1c_u8.to_bytes(writer)?, - Instruction::I32FromU64 => 0x1d_u8.to_bytes(writer)?, - Instruction::I64FromU8 => 0x1e_u8.to_bytes(writer)?, - Instruction::I64FromU16 => 0x1f_u8.to_bytes(writer)?, - Instruction::I64FromU32 => 0x20_u8.to_bytes(writer)?, - Instruction::I64FromU64 => 0x21_u8.to_bytes(writer)?, - - Instruction::StringLiftMemory => 0x22_u8.to_bytes(writer)?, - Instruction::StringLowerMemory => 0x23_u8.to_bytes(writer)?, - Instruction::StringSize => 0x24_u8.to_bytes(writer)?, - - Instruction::RecordLift { type_index } => { - 0x25_u8.to_bytes(writer)?; - (*type_index as u64).to_bytes(writer)? - } - Instruction::RecordLower { type_index } => { - 0x26_u8.to_bytes(writer)?; - (*type_index as u64).to_bytes(writer)? - } - } - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! assert_to_bytes { - ($expr:expr, $expected_output:expr) => {{ - let mut output = vec![]; - - $expr.to_bytes(&mut output).expect(concat!( - "Unable to encode the expression `", - stringify!($expr), - "` to bytes." - )); - - assert_eq!(output.as_slice(), &$expected_output[..]); - }}; - } - - #[test] - fn test_u8() { - assert_to_bytes!(0x01_u8, &[0x01]); - } - - #[test] - fn test_uleb_1_byte() { - assert_to_bytes!(0x01_u64, &[0x01]); - } - - #[test] - fn test_uleb_3_bytes() { - assert_to_bytes!(0x7ffc_u64, &[0xfc, 0xff, 0x01]); - } - - // Examples from Figure 22 of [DWARF 4 - // standard](http://dwarfstd.org/doc/DWARF4.pdf). - #[test] - fn test_uleb_from_dward_standard() { - assert_to_bytes!(2u64, &[2u8]); - assert_to_bytes!(127u64, &[127u8]); - assert_to_bytes!(128u64, &[0x80, 1u8]); - assert_to_bytes!(129u64, &[1u8 | 0x80, 1]); - assert_to_bytes!(130u64, &[2u8 | 0x80, 1]); - assert_to_bytes!(12857u64, &[57u8 | 0x80, 100]); - } - - #[test] - fn test_empty_str() { - assert_to_bytes!("", &[0x00]); - } - - #[test] - fn test_str() { - assert_to_bytes!("abc", &[0x03, 0x61, 0x62, 0x63]); - } - - #[test] - fn test_empty_vec() { - assert_to_bytes!(Vec::::new(), &[0x00]); - } - - #[test] - fn test_vec() { - assert_to_bytes!( - vec!["a", "b", "c"], - &[ - 0x03, // list of 3 items - 0x01, // string of 1 byte - 0x61, // "a" - 0x01, // string of 1 byte - 0x62, // "b" - 0x01, // string of 1 byte - 0x63, // "c" - ] - ); - } - - #[test] - fn test_interface_type() { - assert_to_bytes!(InterfaceType::S8, &[0x00]); - assert_to_bytes!(InterfaceType::S16, &[0x01]); - assert_to_bytes!(InterfaceType::S32, &[0x02]); - assert_to_bytes!(InterfaceType::S64, &[0x03]); - assert_to_bytes!(InterfaceType::U8, &[0x04]); - assert_to_bytes!(InterfaceType::U16, &[0x05]); - assert_to_bytes!(InterfaceType::U32, &[0x06]); - assert_to_bytes!(InterfaceType::U64, &[0x07]); - assert_to_bytes!(InterfaceType::F32, &[0x08]); - assert_to_bytes!(InterfaceType::F64, &[0x09]); - assert_to_bytes!(InterfaceType::String, &[0x0a]); - assert_to_bytes!(InterfaceType::Anyref, &[0x0b]); - assert_to_bytes!(InterfaceType::I32, &[0x0c]); - assert_to_bytes!(InterfaceType::I64, &[0x0d]); - assert_to_bytes!( - InterfaceType::Record(RecordType { - fields: vec1![InterfaceType::String] - }), - &[0x0e, 0x01, 0x0a] - ); - } - - #[test] - fn test_record_type() { - assert_to_bytes!( - RecordType { - fields: vec1![InterfaceType::String] - }, - &[ - 0x01, // 1 field - 0x0a, // String - ] - ); - assert_to_bytes!( - RecordType { - fields: vec1![InterfaceType::String, InterfaceType::I32] - }, - &[ - 0x02, // 2 fields - 0x0a, // String - 0x0c, // I32 - ] - ); - assert_to_bytes!( - RecordType { - fields: vec1![ - InterfaceType::String, - InterfaceType::Record(RecordType { - fields: vec1![InterfaceType::I32, InterfaceType::I32], - }), - InterfaceType::F64, - ], - }, - &[ - 0x03, // 3 fields - 0x0a, // String - 0x0e, // Record - 0x02, // 2 fields - 0x0c, // I32 - 0x0c, // I32 - 0x09, // F64 - ] - ); - } - - #[test] - fn test_interface_kind() { - assert_to_bytes!(InterfaceKind::Type, &[0x00]); - assert_to_bytes!(InterfaceKind::Import, &[0x01]); - assert_to_bytes!(InterfaceKind::Adapter, &[0x02]); - assert_to_bytes!(InterfaceKind::Export, &[0x03]); - assert_to_bytes!(InterfaceKind::Implementation, &[0x04]); - } - - #[test] - fn test_export() { - assert_to_bytes!( - Export { - name: "abc", - function_type: 0, - }, - &[ - 0x03, // string of length 3 - 0x61, // "a" - 0x62, // "b" - 0x63, // "c" - 0x00, // function type - ] - ); - } - - #[test] - fn test_type_function() { - assert_to_bytes!( - Type::Function { - inputs: vec![InterfaceType::I32, InterfaceType::I64], - outputs: vec![InterfaceType::S32], - }, - &[ - 0x00, // function type - 0x02, // list of 2 items - 0x0c, // I32 - 0x0d, // I64 - 0x01, // list of 1 items - 0x02, // I64 - ] - ); - } - - #[test] - fn test_type_record() { - assert_to_bytes!( - Type::Record(RecordType { - fields: vec1![InterfaceType::I32, InterfaceType::I64], - }), - &[ - 0x01, // record type - 0x02, // list of 2 items - 0x0c, // I32 - 0x0d, // I64 - ] - ); - } - - #[test] - fn test_import() { - assert_to_bytes!( - Import { - namespace: "a", - name: "b", - signature_type: 0, - }, - &[ - 0x01, // string of length 1 - 0x61, // "a" - 0x01, // string of length 1 - 0x62, // "b" - 0x00, // signature typr - ] - ); - } - - #[test] - fn test_adapter() { - assert_to_bytes!( - Adapter { - function_type: 0, - instructions: vec![Instruction::ArgumentGet { index: 1 }], - }, - &[ - 0x00, // function type - 0x01, // list of 1 item - 0x00, 0x01, // ArgumentGet { index: 1 } - ] - ); - } - - #[test] - fn test_interfaces() { - assert_to_bytes!( - Interfaces { - types: vec![Type::Function { - inputs: vec![InterfaceType::S8], - outputs: vec![InterfaceType::S16], - }], - imports: vec![Import { - namespace: "ab", - name: "c", - signature_type: 0, - }], - 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 - 0x00, // function 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, // function type - // - 0x04, // implementation section - 0x01, // 1 implementation - 0x02, // core function type - 0x03, // adapter function type - ] - ); - } - - #[test] - fn test_instructions() { - assert_to_bytes!( - vec![ - Instruction::ArgumentGet { index: 1 }, - Instruction::CallCore { function_index: 1 }, - Instruction::S8FromI32, - Instruction::S8FromI64, - Instruction::S16FromI32, - Instruction::S16FromI64, - Instruction::S32FromI32, - Instruction::S32FromI64, - Instruction::S64FromI32, - Instruction::S64FromI64, - Instruction::I32FromS8, - Instruction::I32FromS16, - Instruction::I32FromS32, - Instruction::I32FromS64, - Instruction::I64FromS8, - Instruction::I64FromS16, - Instruction::I64FromS32, - Instruction::I64FromS64, - Instruction::U8FromI32, - Instruction::U8FromI64, - Instruction::U16FromI32, - Instruction::U16FromI64, - Instruction::U32FromI32, - Instruction::U32FromI64, - Instruction::U64FromI32, - Instruction::U64FromI64, - Instruction::I32FromU8, - Instruction::I32FromU16, - Instruction::I32FromU32, - Instruction::I32FromU64, - Instruction::I64FromU8, - Instruction::I64FromU16, - Instruction::I64FromU32, - Instruction::I64FromU64, - Instruction::StringLiftMemory, - Instruction::StringLowerMemory, - Instruction::StringSize, - Instruction::RecordLift { type_index: 1 }, - Instruction::RecordLower { type_index: 1 }, - ], - &[ - 0x27, // list of 39 items - 0x00, 0x01, // ArgumentGet { index: 1 } - 0x01, 0x01, // CallCore { function_index: 1 } - 0x02, // S8FromI32 - 0x03, // S8FromI64 - 0x04, // S16FromI32 - 0x05, // S16FromI64 - 0x06, // S32FromI32 - 0x07, // S32FromI64 - 0x08, // S64FromI32 - 0x09, // S64FromI64 - 0x0a, // I32FromS8 - 0x0b, // I32FromS16 - 0x0c, // I32FromS32 - 0x0d, // I32FromS64 - 0x0e, // I64FromS8 - 0x0f, // I64FromS16 - 0x10, // I64FromS32 - 0x11, // I64FromS64 - 0x12, // U8FromI32 - 0x13, // U8FromI64 - 0x14, // U16FromI32 - 0x15, // U16FromI64 - 0x16, // U32FromI32 - 0x17, // U32FromI64 - 0x18, // U64FromI32 - 0x19, // U64FromI64 - 0x1a, // I32FromU8 - 0x1b, // I32FromU16 - 0x1c, // I32FromU32 - 0x1d, // I32FromU64 - 0x1e, // I64FromU8 - 0x1f, // I64FromU16 - 0x20, // I64FromU32 - 0x21, // I64FromU64 - 0x22, // StringLiftMemory - 0x23, // StringLowerMemory - 0x24, // StringSize - 0x025, 0x01, // RecordLift { type_index: 1 } - 0x026, 0x01, // RecordLower { type_index: 1 } - ] - ); - } -} diff --git a/lib/interface-types/src/encoders/mod.rs b/lib/interface-types/src/encoders/mod.rs deleted file mode 100644 index a85181942..000000000 --- a/lib/interface-types/src/encoders/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Writes the AST into a particular format; for instance, -//! `encoders::wat` writes the AST into a string representing WIT with -//! its textual format. - -pub mod binary; -pub mod wat; diff --git a/lib/interface-types/src/encoders/wat.rs b/lib/interface-types/src/encoders/wat.rs deleted file mode 100644 index 6d58e0444..000000000 --- a/lib/interface-types/src/encoders/wat.rs +++ /dev/null @@ -1,641 +0,0 @@ -//! Writes the AST into a string representing WIT with its textual format. -//! -//! # Example -//! -//! ```rust -//! use wasmer_interface_types::{ -//! ast::{Adapter, Export, Implementation, Import, Interfaces, Type}, -//! encoders::wat::*, -//! interpreter::Instruction, -//! types::InterfaceType, -//! }; -//! -//! let input: String = (&Interfaces { -//! types: vec![Type::Function { -//! 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#";; Types -//! (@interface type (func -//! (param i32) -//! (result s8))) -//! -//! ;; Imports -//! (@interface import "ns" "foo" (func (type 0))) -//! -//! ;; Adapters -//! (@interface func (type 0) -//! arg.get 42) -//! -//! ;; Exports -//! (@interface export "bar" (func 0)) -//! -//! ;; Implementations -//! (@interface implement (func 0) (func 1))"#; -//! -//! assert_eq!(input, output); -//! ``` - -use crate::{ast::*, interpreter::Instruction, types::*}; -use std::string::ToString; - -/// Encode an `InterfaceType` into a string. -impl ToString for &InterfaceType { - fn to_string(&self) -> String { - match self { - InterfaceType::S8 => "s8".to_string(), - InterfaceType::S16 => "s16".to_string(), - InterfaceType::S32 => "s32".to_string(), - InterfaceType::S64 => "s64".to_string(), - InterfaceType::U8 => "u8".to_string(), - InterfaceType::U16 => "u16".to_string(), - InterfaceType::U32 => "u32".to_string(), - InterfaceType::U64 => "u64".to_string(), - InterfaceType::F32 => "f32".to_string(), - InterfaceType::F64 => "f64".to_string(), - InterfaceType::String => "string".to_string(), - InterfaceType::Anyref => "anyref".to_string(), - InterfaceType::I32 => "i32".to_string(), - 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. -impl ToString for &Instruction { - fn to_string(&self) -> String { - match self { - Instruction::ArgumentGet { index } => format!("arg.get {}", index), - Instruction::CallCore { function_index } => format!("call-core {}", function_index), - Instruction::S8FromI32 => "s8.from_i32".into(), - Instruction::S8FromI64 => "s8.from_i64".into(), - Instruction::S16FromI32 => "s16.from_i32".into(), - Instruction::S16FromI64 => "s16.from_i64".into(), - Instruction::S32FromI32 => "s32.from_i32".into(), - Instruction::S32FromI64 => "s32.from_i64".into(), - Instruction::S64FromI32 => "s64.from_i32".into(), - Instruction::S64FromI64 => "s64.from_i64".into(), - Instruction::I32FromS8 => "i32.from_s8".into(), - Instruction::I32FromS16 => "i32.from_s16".into(), - Instruction::I32FromS32 => "i32.from_s32".into(), - Instruction::I32FromS64 => "i32.from_s64".into(), - Instruction::I64FromS8 => "i64.from_s8".into(), - Instruction::I64FromS16 => "i64.from_s16".into(), - Instruction::I64FromS32 => "i64.from_s32".into(), - Instruction::I64FromS64 => "i64.from_s64".into(), - Instruction::U8FromI32 => "u8.from_i32".into(), - Instruction::U8FromI64 => "u8.from_i64".into(), - Instruction::U16FromI32 => "u16.from_i32".into(), - Instruction::U16FromI64 => "u16.from_i64".into(), - Instruction::U32FromI32 => "u32.from_i32".into(), - Instruction::U32FromI64 => "u32.from_i64".into(), - Instruction::U64FromI32 => "u64.from_i32".into(), - Instruction::U64FromI64 => "u64.from_i64".into(), - Instruction::I32FromU8 => "i32.from_u8".into(), - Instruction::I32FromU16 => "i32.from_u16".into(), - Instruction::I32FromU32 => "i32.from_u32".into(), - Instruction::I32FromU64 => "i32.from_u64".into(), - Instruction::I64FromU8 => "i64.from_u8".into(), - Instruction::I64FromU16 => "i64.from_u16".into(), - Instruction::I64FromU32 => "i64.from_u32".into(), - Instruction::I64FromU64 => "i64.from_u64".into(), - Instruction::StringLiftMemory => "string.lift_memory".into(), - Instruction::StringLowerMemory => "string.lower_memory".into(), - Instruction::StringSize => "string.size".into(), - Instruction::RecordLift { type_index } => format!("record.lift {}", type_index), - Instruction::RecordLower { type_index } => format!("record.lower {}", type_index), - } - } -} - -/// Encode a list of `InterfaceType` representing inputs into a -/// string. -fn input_types_to_param(input_types: &[InterfaceType]) -> String { - if input_types.is_empty() { - "".into() - } else { - format!( - "\n (param{})", - input_types - .iter() - .fold(String::new(), |mut accumulator, interface_type| { - accumulator.push(' '); - accumulator.push_str(&interface_type.to_string()); - accumulator - }) - ) - } -} - -/// Encode a list of `InterfaceType` representing outputs into a -/// string. -fn output_types_to_result(output_types: &[InterfaceType]) -> String { - if output_types.is_empty() { - "".into() - } else { - format!( - "\n (result{})", - output_types - .iter() - .fold(String::new(), |mut accumulator, interface_type| { - accumulator.push(' '); - accumulator.push_str(&interface_type.to_string()); - accumulator - }) - ) - } -} - -/// Encode a `Type` into a string. -impl<'input> ToString for &Type { - fn to_string(&self) -> String { - match self { - Type::Function { inputs, outputs } => format!( - r#"(@interface type (func{inputs}{outputs}))"#, - inputs = input_types_to_param(&inputs), - outputs = output_types_to_result(&outputs), - ), - - Type::Record(record_type) => format!( - r#"(@interface type ({record_type}))"#, - record_type = record_type.to_string(), - ), - } - } -} - -/// Encode an `Import` into a string. -impl<'input> ToString for &Import<'input> { - fn to_string(&self) -> String { - format!( - r#"(@interface import "{namespace}" "{name}" (func (type {type})))"#, - namespace = self.namespace, - name = self.name, - type = self.signature_type, - ) - } -} - -/// Encode an `Adapter` into a string. -impl ToString for &Adapter { - fn to_string(&self) -> String { - format!( - r#"(@interface func (type {function_type}){instructions})"#, - function_type = self.function_type, - instructions = - self.instructions - .iter() - .fold(String::new(), |mut accumulator, instruction| { - accumulator.push_str("\n "); - accumulator.push_str(&instruction.to_string()); - accumulator - }), - ) - } -} - -/// Encode an `Export` into a string. -impl<'input> ToString for &Export<'input> { - fn to_string(&self) -> String { - format!( - r#"(@interface export "{name}" (func {type}))"#, - name = self.name, - type = self.function_type, - ) - } -} - -/// Encode an `Implementation` into a string. -impl<'input> ToString for &Implementation { - fn to_string(&self) -> String { - format!( - r#"(@interface implement (func {core_function_type}) (func {adapter_function_type}))"#, - core_function_type = self.core_function_type, - adapter_function_type = self.adapter_function_type, - ) - } -} - -/// Encode an `Interfaces` into a string. -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 imports = self - .imports - .iter() - .fold(String::new(), |mut accumulator, import| { - accumulator.push('\n'); - accumulator.push_str(&import.to_string()); - accumulator - }); - - let adapters = self - .adapters - .iter() - .fold(String::new(), |mut accumulator, adapter| { - accumulator.push('\n'); - accumulator.push_str(&adapter.to_string()); - accumulator - }); - - let exports = self - .exports - .iter() - .fold(String::new(), |mut accumulator, export| { - accumulator.push('\n'); - accumulator.push_str(&export.to_string()); - accumulator - }); - - let implementations = - self.implementations - .iter() - .fold(String::new(), |mut accumulator, implementation| { - accumulator.push('\n'); - accumulator.push_str(&implementation.to_string()); - accumulator - }); - - 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 - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_interface_types() { - let inputs: Vec = vec![ - (&InterfaceType::S8).to_string(), - (&InterfaceType::S16).to_string(), - (&InterfaceType::S32).to_string(), - (&InterfaceType::S64).to_string(), - (&InterfaceType::U8).to_string(), - (&InterfaceType::U16).to_string(), - (&InterfaceType::U32).to_string(), - (&InterfaceType::U64).to_string(), - (&InterfaceType::F32).to_string(), - (&InterfaceType::F64).to_string(), - (&InterfaceType::String).to_string(), - (&InterfaceType::Anyref).to_string(), - (&InterfaceType::I32).to_string(), - (&InterfaceType::I64).to_string(), - (&InterfaceType::Record(RecordType { - fields: vec1![InterfaceType::String], - })) - .to_string(), - ]; - let outputs = vec![ - "s8", - "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: vec1![InterfaceType::String], - }) - .to_string(), - (&RecordType { - fields: vec1![InterfaceType::String, InterfaceType::I32], - }) - .to_string(), - (&RecordType { - fields: vec1![ - InterfaceType::String, - InterfaceType::Record(RecordType { - fields: vec1![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); - } - - #[test] - fn test_instructions() { - let inputs: Vec = vec![ - (&Instruction::ArgumentGet { index: 7 }).to_string(), - (&Instruction::CallCore { function_index: 7 }).to_string(), - (&Instruction::S8FromI32).to_string(), - (&Instruction::S8FromI64).to_string(), - (&Instruction::S16FromI32).to_string(), - (&Instruction::S16FromI64).to_string(), - (&Instruction::S32FromI32).to_string(), - (&Instruction::S32FromI64).to_string(), - (&Instruction::S64FromI32).to_string(), - (&Instruction::S64FromI64).to_string(), - (&Instruction::I32FromS8).to_string(), - (&Instruction::I32FromS16).to_string(), - (&Instruction::I32FromS32).to_string(), - (&Instruction::I32FromS64).to_string(), - (&Instruction::I64FromS8).to_string(), - (&Instruction::I64FromS16).to_string(), - (&Instruction::I64FromS32).to_string(), - (&Instruction::I64FromS64).to_string(), - (&Instruction::U8FromI32).to_string(), - (&Instruction::U8FromI64).to_string(), - (&Instruction::U16FromI32).to_string(), - (&Instruction::U16FromI64).to_string(), - (&Instruction::U32FromI32).to_string(), - (&Instruction::U32FromI64).to_string(), - (&Instruction::U64FromI32).to_string(), - (&Instruction::U64FromI64).to_string(), - (&Instruction::I32FromU8).to_string(), - (&Instruction::I32FromU16).to_string(), - (&Instruction::I32FromU32).to_string(), - (&Instruction::I32FromU64).to_string(), - (&Instruction::I64FromU8).to_string(), - (&Instruction::I64FromU16).to_string(), - (&Instruction::I64FromU32).to_string(), - (&Instruction::I64FromU64).to_string(), - (&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", - "call-core 7", - "s8.from_i32", - "s8.from_i64", - "s16.from_i32", - "s16.from_i64", - "s32.from_i32", - "s32.from_i64", - "s64.from_i32", - "s64.from_i64", - "i32.from_s8", - "i32.from_s16", - "i32.from_s32", - "i32.from_s64", - "i64.from_s8", - "i64.from_s16", - "i64.from_s32", - "i64.from_s64", - "u8.from_i32", - "u8.from_i64", - "u16.from_i32", - "u16.from_i64", - "u32.from_i32", - "u32.from_i64", - "u64.from_i32", - "u64.from_i64", - "i32.from_u8", - "i32.from_u16", - "i32.from_u32", - "i32.from_u64", - "i64.from_u8", - "i64.from_u16", - "i64.from_u32", - "i64.from_u64", - "string.lift_memory", - "string.lower_memory", - "string.size", - "record.lift 42", - "record.lower 42", - ]; - - assert_eq!(inputs, outputs); - } - - #[test] - fn test_types() { - let inputs: Vec = vec![ - (&Type::Function { - inputs: vec![InterfaceType::I32, InterfaceType::F32], - outputs: vec![InterfaceType::I32], - }) - .to_string(), - (&Type::Function { - inputs: vec![InterfaceType::I32], - outputs: vec![], - }) - .to_string(), - (&Type::Function { - inputs: vec![], - outputs: vec![InterfaceType::I32], - }) - .to_string(), - (&Type::Function { - inputs: vec![], - outputs: vec![], - }) - .to_string(), - (&Type::Record(RecordType { - fields: vec1![InterfaceType::String, InterfaceType::I32], - })) - .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))"#, - r#"(@interface type (record (field string) (field i32)))"#, - ]; - - assert_eq!(inputs, outputs); - } - - #[test] - fn test_exports() { - let input = (&Export { - name: "foo", - function_type: 0, - }) - .to_string(); - let output = r#"(@interface export "foo" (func 0))"#; - - assert_eq!(input, output); - } - - #[test] - fn test_imports() { - let input = (&Import { - namespace: "ns", - name: "foo", - signature_type: 0, - }) - .to_string(); - let output = r#"(@interface import "ns" "foo" (func (type 0)))"#; - - assert_eq!(input, output); - } - - #[test] - 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!(input, output); - } - - #[test] - fn test_interfaces() { - let input: String = (&Interfaces { - types: vec![Type::Function { - 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#";; Types -(@interface type (func - (param i32) - (result s8))) - -;; Imports -(@interface import "ns" "foo" (func (type 0))) - -;; Adapters -(@interface func (type 0) - arg.get 42) - -;; Exports -(@interface export "bar" (func 0)) - -;; Implementations -(@interface implement (func 0) (func 1))"#; - - assert_eq!(input, output); - } -} diff --git a/lib/interface-types/src/errors.rs b/lib/interface-types/src/errors.rs deleted file mode 100644 index 0762a2437..000000000 --- a/lib/interface-types/src/errors.rs +++ /dev/null @@ -1,269 +0,0 @@ -//! The error module contains all the data structures that represent -//! an error. - -use crate::{ast::TypeKind, interpreter::Instruction, types::InterfaceType}; -use std::{ - error::Error, - fmt::{self, Display, Formatter}, - num::TryFromIntError, - result::Result, - string::{self, ToString}, -}; - -/// A type alias for instruction's results. -pub type InstructionResult = Result; - -/// A type alias for the interpreter result. -pub type InterpreterResult = Result; - -/// Structure to represent errors when casting from an `InterfaceType` -/// to a native value. -#[derive(Debug)] -pub struct WasmValueNativeCastError { - /// The initial type. - pub from: InterfaceType, - - /// The targeted type. - /// - /// `InterfaceType` is used to represent the native type by - /// associativity. - pub to: InterfaceType, -} - -impl Error for WasmValueNativeCastError {} - -impl Display for WasmValueNativeCastError { - fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - write!(formatter, "{:?}", self) - } -} - -/// Structure to represent the errors for instructions. -#[derive(Debug)] -pub struct InstructionError { - /// The instruction that raises the error. - pub instruction: Instruction, - - /// The error kind. - pub error_kind: InstructionErrorKind, -} - -impl InstructionError { - pub(crate) fn new(instruction: Instruction, error_kind: InstructionErrorKind) -> Self { - Self { - instruction, - error_kind, - } - } -} - -impl Error for InstructionError {} - -impl Display for InstructionError { - fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - write!( - formatter, - "`{}` {}", - (&self.instruction).to_string(), - self.error_kind - ) - } -} - -/// The kind of instruction errors. -#[derive(Debug)] -pub enum InstructionErrorKind { - /// The instruction needs to read an invocation input at index `index`, but it's missing. - InvocationInputIsMissing { - /// The invocation input index. - index: u32, - }, - - /// Failed to cast from a WIT value to a native value. - ToNative(WasmValueNativeCastError), - - /// Failed to cast from `from` to `to`. - LoweringLifting { - /// The initial type. - from: InterfaceType, - - /// The targeted type. - to: InterfaceType, - }, - - /// Read a value from the stack, but it doesn't have the expected - /// type. - InvalidValueOnTheStack { - /// The expected type. - expected_type: InterfaceType, - - /// The received type. - received_type: InterfaceType, - }, - - /// Need to read some values from the stack, but it doesn't - /// contain enough data. - StackIsTooSmall { - /// The number of values that were needed. - needed: usize, - }, - - /// The local or import function doesn't exist. - LocalOrImportIsMissing { - /// The local or import function index. - function_index: u32, - }, - - /// Values given to a local or import function doesn't match the - /// function signature. - LocalOrImportSignatureMismatch { - /// The local or import function index. - function_index: u32, - - /// The expected signature. - expected: (Vec, Vec), - - /// The received signature. - received: (Vec, Vec), - }, - - /// Failed to call a local or import function. - LocalOrImportCall { - /// The local or import function index that has been called. - function_index: u32, - }, - - /// The memory doesn't exist. - MemoryIsMissing { - /// The memory indeX. - memory_index: u32, - }, - - /// Tried to read out of bounds of the memory. - MemoryOutOfBoundsAccess { - /// The access index. - index: usize, - - /// The memory length. - length: usize, - }, - - /// The string contains invalid UTF-8 encoding. - String(string::FromUtf8Error), - - /// Out of range integral type conversion attempted. - NegativeValue { - /// The variable name that triggered the error. - subject: &'static str, - }, - - /// The type doesn't exist. - TypeIsMissing { - /// The type index. - type_index: u32, - }, - - /// Read a type that has an unexpected type. - InvalidTypeKind { - /// The expected kind. - expected_kind: TypeKind, - - /// The received kind. - received_kind: TypeKind, - }, -} - -impl Error for InstructionErrorKind {} - -impl Display for InstructionErrorKind { - fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { - match self { - Self::InvocationInputIsMissing { index } => write!( - formatter, - "cannot access invocation inputs #{} because it doesn't exist", - index - ), - - Self::ToNative(WasmValueNativeCastError { from, .. }) => write!( - formatter, - "failed to cast the WIT value `{:?}` to its native type", - from, - ), - - Self::LoweringLifting { from, to } => { - write!(formatter, "failed to cast `{:?}` to `{:?}`", from, to) - } - - Self::InvalidValueOnTheStack { - expected_type, - received_type, - } => write!( - formatter, - "read a value of type `{:?}` from the stack, but the type `{:?}` was expected", - received_type, expected_type, - ), - - Self::StackIsTooSmall { needed } => write!( - formatter, - "needed to read `{}` value(s) from the stack, but it doesn't contain enough data", - needed - ), - - Self::LocalOrImportIsMissing { function_index } => write!( - formatter, - "the local or import function `{}` doesn't exist", - function_index - ), - - Self::LocalOrImportSignatureMismatch { function_index, expected, received } => write!( - formatter, - "the local or import function `{}` has the signature `{:?} -> {:?}` but it received values of kind `{:?} -> {:?}`", - function_index, expected.0, expected.1, received.0, received.1, - ), - - Self::LocalOrImportCall { function_index } => write!( - formatter, - "failed while calling the local or import function `{}`", - function_index - ), - - Self::MemoryIsMissing { memory_index } => write!( - formatter, - "memory `{}` does not exist", - memory_index, - ), - - Self::MemoryOutOfBoundsAccess { index, length } => write!( - formatter, - "read out of the memory bounds (index {} > memory length {})", - index, length, - ), - - Self::String(error) => write!(formatter, "{}", error), - - Self::NegativeValue { subject } => write!( - formatter, - "attempted to convert `{}` but it appears to be a negative value", - subject - ), - - Self::TypeIsMissing { type_index } => write!( - formatter, - "the type `{}` doesn't exist", - type_index - ), - - Self::InvalidTypeKind { expected_kind, received_kind } => write!( - formatter, - "read a type of kind `{:?}`, but the kind `{:?}` was expected", - received_kind, expected_kind - ), - } - } -} - -impl From<(TryFromIntError, &'static str)> for InstructionErrorKind { - fn from((_, subject): (TryFromIntError, &'static str)) -> Self { - InstructionErrorKind::NegativeValue { subject } - } -} diff --git a/lib/interface-types/src/interpreter/instructions/argument_get.rs b/lib/interface-types/src/interpreter/instructions/argument_get.rs deleted file mode 100644 index 3b95405be..000000000 --- a/lib/interface-types/src/interpreter/instructions/argument_get.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::Instruction, -}; - -executable_instruction!( - argument_get(index: u32, instruction: Instruction) -> _ { - move |runtime| -> _ { - let invocation_inputs = runtime.invocation_inputs; - - if (index as usize) >= invocation_inputs.len() { - return Err(InstructionError::new( - instruction, - InstructionErrorKind::InvocationInputIsMissing { index }, - )); - } - - runtime.stack.push(invocation_inputs[index as usize].clone()); - - Ok(()) - } - } -); - -#[cfg(test)] -mod tests { - test_executable_instruction!( - test_argument_get = - instructions: [Instruction::ArgumentGet { index: 0 }], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_argument_get__twice = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - ], - invocation_inputs: [ - InterfaceValue::I32(7), - InterfaceValue::I32(42), - ], - instance: Instance::new(), - stack: [ - InterfaceValue::I32(7), - InterfaceValue::I32(42), - ], - ); - - test_executable_instruction!( - test_argument_get__invalid_index = - instructions: [Instruction::ArgumentGet { index: 1 }], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - error: "`arg.get 1` cannot access invocation inputs #1 because it doesn't exist" - ); -} diff --git a/lib/interface-types/src/interpreter/instructions/call_core.rs b/lib/interface-types/src/interpreter/instructions/call_core.rs deleted file mode 100644 index fb72b3334..000000000 --- a/lib/interface-types/src/interpreter/instructions/call_core.rs +++ /dev/null @@ -1,188 +0,0 @@ -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 index = FunctionIndex::new(function_index as usize); - - let local_or_import = instance.local_or_import(index).ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::LocalOrImportIsMissing { - function_index: function_index, - }, - ) - })?; - let inputs_cardinality = local_or_import.inputs_cardinality(); - - let inputs = runtime.stack.pop(inputs_cardinality).ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { - needed: inputs_cardinality, - }, - ) - })?; - let input_types = inputs - .iter() - .map(Into::into) - .collect::>(); - - if input_types != local_or_import.inputs() { - return Err(InstructionError::new( - instruction, - InstructionErrorKind::LocalOrImportSignatureMismatch { - function_index: function_index, - expected: (local_or_import.inputs().to_vec(), vec![]), - received: (input_types, vec![]), - }, - )); - } - - let outputs = local_or_import.call(&inputs).map_err(|_| { - InstructionError::new( - instruction, - InstructionErrorKind::LocalOrImportCall { - function_index: function_index, - }, - ) - })?; - - for output in outputs.into_iter() { - runtime.stack.push(output) - } - - Ok(()) - } - } -); - -#[cfg(test)] -mod tests { - test_executable_instruction!( - test_call_core = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::CallCore { function_index: 42 }, - ], - invocation_inputs: [ - InterfaceValue::I32(3), - InterfaceValue::I32(4), - ], - instance: Instance::new(), - stack: [InterfaceValue::I32(12)], - ); - - test_executable_instruction!( - test_call_core__invalid_local_import_index = - instructions: [ - Instruction::CallCore { function_index: 42 }, - ], - invocation_inputs: [ - InterfaceValue::I32(3), - InterfaceValue::I32(4), - ], - instance: Default::default(), - error: r#"`call-core 42` the local or import function `42` doesn't exist"#, - ); - - test_executable_instruction!( - test_call_core__stack_is_too_small = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::CallCore { function_index: 42 }, - // ^^ `42` expects 2 values on the stack, only one is present - ], - invocation_inputs: [ - InterfaceValue::I32(3), - InterfaceValue::I32(4), - ], - instance: Instance::new(), - error: r#"`call-core 42` needed to read `2` value(s) from the stack, but it doesn't contain enough data"#, - ); - - test_executable_instruction!( - test_call_core__invalid_types_in_the_stack = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::CallCore { function_index: 42 }, - ], - invocation_inputs: [ - InterfaceValue::I32(3), - InterfaceValue::I64(4), - // ^^^ mismatch with `42` signature - ], - instance: Instance::new(), - error: r#"`call-core 42` the local or import function `42` has the signature `[I32, I32] -> []` but it received values of kind `[I32, I64] -> []`"#, - ); - - test_executable_instruction!( - test_call_core__failure_when_calling = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::CallCore { function_index: 42 }, - ], - invocation_inputs: [ - InterfaceValue::I32(3), - InterfaceValue::I32(4), - ], - instance: Instance { - locals_or_imports: { - let mut hashmap = HashMap::new(); - hashmap.insert( - 42, - LocalImport { - inputs: vec![InterfaceType::I32, InterfaceType::I32], - outputs: vec![InterfaceType::I32], - function: |_| Err(()), - // ^^^^^^^ function fails - }, - ); - - hashmap - }, - ..Default::default() - }, - error: r#"`call-core 42` failed while calling the local or import function `42`"#, - ); - - test_executable_instruction!( - test_call_core__void = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::CallCore { function_index: 42 }, - ], - invocation_inputs: [ - InterfaceValue::I32(3), - InterfaceValue::I32(4), - ], - instance: Instance { - locals_or_imports: { - let mut hashmap = HashMap::new(); - hashmap.insert( - 42, - LocalImport { - inputs: vec![InterfaceType::I32, InterfaceType::I32], - outputs: vec![InterfaceType::I32], - function: |_| Ok(vec![]), - // ^^^^^^^^^^ void - }, - ); - - hashmap - }, - ..Default::default() - }, - stack: [], - ); -} diff --git a/lib/interface-types/src/interpreter/instructions/mod.rs b/lib/interface-types/src/interpreter/instructions/mod.rs deleted file mode 100644 index cddc16518..000000000 --- a/lib/interface-types/src/interpreter/instructions/mod.rs +++ /dev/null @@ -1,352 +0,0 @@ -mod argument_get; -mod call_core; -mod numbers; -mod records; -mod strings; - -use crate::{ - errors::{InstructionError, InstructionErrorKind, InstructionResult, WasmValueNativeCastError}, - values::{InterfaceValue, NativeType}, -}; -pub(crate) use argument_get::argument_get; -pub(crate) use call_core::call_core; -pub(crate) use numbers::*; -pub(crate) use records::*; -use std::convert::TryFrom; -pub(crate) use strings::*; - -/// Represents all the possible WIT instructions. -#[derive(PartialEq, Debug, Clone, Copy)] -pub enum Instruction { - /// The `arg.get` instruction. - ArgumentGet { - /// The argument index. - index: u32, - }, - - /// The `call-core` instruction. - CallCore { - /// The function index. - function_index: u32, - }, - - /// The `s8.from_i32` instruction. - S8FromI32, - - /// The `s8.from_i64` instruction. - S8FromI64, - - /// The `s16.from_i32` instruction. - S16FromI32, - - /// The `s16.from_i64` instruction. - S16FromI64, - - /// The `s32.from_i32` instruction. - S32FromI32, - - /// The `s32.from_i64` instruction. - S32FromI64, - - /// The `s64.from_i32` instruction. - S64FromI32, - - /// The `s64.from_i64` instruction. - S64FromI64, - - /// The `i32.from_s8` instruction. - I32FromS8, - - /// The `i32.from_s16` instruction. - I32FromS16, - - /// The `i32.from_s32` instruction. - I32FromS32, - - /// The `i32.from_s64` instruction. - I32FromS64, - - /// The `i64.from_s8` instruction. - I64FromS8, - - /// The `i64.from_s16` instruction. - I64FromS16, - - /// The `i64.from_s32` instruction. - I64FromS32, - - /// The `i64.from_s64` instruction. - I64FromS64, - - /// The `u8.from_i32` instruction. - U8FromI32, - - /// The `u8.from_i64` instruction. - U8FromI64, - - /// The `u16.from_i32` instruction. - U16FromI32, - - /// The `u16.from_i64` instruction. - U16FromI64, - - /// The `u32.from_i32` instruction. - U32FromI32, - - /// The `u32.from_i64` instruction. - U32FromI64, - - /// The `u64.from_i32` instruction. - U64FromI32, - - /// The `u64.from_i64` instruction. - U64FromI64, - - /// The `i32.from_u8` instruction. - I32FromU8, - - /// The `i32.from_u16` instruction. - I32FromU16, - - /// The `i32.from_u32` instruction. - I32FromU32, - - /// The `i32.from_u64` instruction. - I32FromU64, - - /// The `i64.from_u8` instruction. - I64FromU8, - - /// The `i64.from_u16` instruction. - I64FromU16, - - /// The `i64.from_u32` instruction. - I64FromU32, - - /// The `i64.from_u64` instruction. - I64FromU64, - - /// The `string.lift_memory` instruction. - StringLiftMemory, - - /// The `string.lower_memory` instruction. - StringLowerMemory, - - /// The `string.size` instruction. - StringSize, - - /// The `record.lift` instruction. - RecordLift { - /// The type index of the record. - type_index: u32, - }, - - /// The `record.lower` instruction. - RecordLower { - /// The type index of the record. - type_index: u32, - }, -} - -/// Just a short helper to map the error of a cast from an -/// `InterfaceValue` to a native value. -pub(crate) fn to_native<'a, T>( - wit_value: &'a InterfaceValue, - instruction: Instruction, -) -> InstructionResult -where - T: NativeType + TryFrom<&'a InterfaceValue, Error = WasmValueNativeCastError>, -{ - T::try_from(wit_value) - .map_err(|error| InstructionError::new(instruction, InstructionErrorKind::ToNative(error))) -} - -#[cfg(test)] -pub(crate) mod tests { - use crate::{ast::*, interpreter::wasm, types::*, values::*}; - use std::{cell::Cell, collections::HashMap, convert::TryInto, ops::Deref, rc::Rc}; - - pub(crate) struct Export { - pub(crate) inputs: Vec, - pub(crate) outputs: Vec, - pub(crate) function: fn(arguments: &[InterfaceValue]) -> Result, ()>, - } - - impl wasm::structures::Export for Export { - fn inputs_cardinality(&self) -> usize { - self.inputs.len() as usize - } - - fn outputs_cardinality(&self) -> usize { - self.outputs.len() - } - - fn inputs(&self) -> &[InterfaceType] { - &self.inputs - } - - fn outputs(&self) -> &[InterfaceType] { - &self.outputs - } - - fn call(&self, arguments: &[InterfaceValue]) -> Result, ()> { - (self.function)(arguments) - } - } - - pub(crate) struct LocalImport { - pub(crate) inputs: Vec, - pub(crate) outputs: Vec, - pub(crate) function: fn(arguments: &[InterfaceValue]) -> Result, ()>, - } - - impl wasm::structures::LocalImport for LocalImport { - fn inputs_cardinality(&self) -> usize { - self.inputs.len() - } - - fn outputs_cardinality(&self) -> usize { - self.outputs.len() - } - - fn inputs(&self) -> &[InterfaceType] { - &self.inputs - } - - fn outputs(&self) -> &[InterfaceType] { - &self.outputs - } - - fn call(&self, arguments: &[InterfaceValue]) -> Result, ()> { - (self.function)(arguments) - } - } - - #[derive(Default, Clone)] - pub(crate) struct MemoryView(Rc>>); - - impl wasm::structures::MemoryView for MemoryView {} - - impl Deref for MemoryView { - type Target = [Cell]; - - fn deref(&self) -> &Self::Target { - self.0.as_slice() - } - } - - #[derive(Default)] - pub(crate) struct Memory { - pub(crate) view: MemoryView, - } - - impl Memory { - pub(crate) fn new(data: Vec>) -> Self { - Self { - view: MemoryView(Rc::new(data)), - } - } - } - - impl wasm::structures::Memory for Memory { - fn view(&self) -> MemoryView { - self.view.clone() - } - } - - #[derive(Default)] - pub(crate) struct Instance { - pub(crate) exports: HashMap, - pub(crate) locals_or_imports: HashMap, - pub(crate) memory: Memory, - pub(crate) wit_types: Vec, - } - - impl Instance { - pub(crate) fn new() -> Self { - Self { - exports: { - let mut hashmap = HashMap::new(); - hashmap.insert( - "sum".into(), - Export { - inputs: vec![InterfaceType::I32, InterfaceType::I32], - outputs: vec![InterfaceType::I32], - function: |arguments: &[InterfaceValue]| { - let a: i32 = (&arguments[0]).try_into().unwrap(); - let b: i32 = (&arguments[1]).try_into().unwrap(); - - Ok(vec![InterfaceValue::I32(a + b)]) - }, - }, - ); - - hashmap - }, - locals_or_imports: { - let mut hashmap = HashMap::new(); - // sum - hashmap.insert( - 42, - LocalImport { - inputs: vec![InterfaceType::I32, InterfaceType::I32], - outputs: vec![InterfaceType::I32], - function: |arguments: &[InterfaceValue]| { - let a: i32 = (&arguments[0]).try_into().unwrap(); - let b: i32 = (&arguments[1]).try_into().unwrap(); - - Ok(vec![InterfaceValue::I32(a * b)]) - }, - }, - ); - // string allocator - hashmap.insert( - 43, - LocalImport { - inputs: vec![InterfaceType::I32], - outputs: vec![InterfaceType::I32], - function: |arguments: &[InterfaceValue]| { - let _size: i32 = (&arguments[0]).try_into().unwrap(); - - Ok(vec![InterfaceValue::I32(0)]) - }, - }, - ); - - hashmap - }, - memory: Memory::new(vec![Cell::new(0); 128]), - wit_types: vec![Type::Record(RecordType { - fields: vec1![ - InterfaceType::I32, - InterfaceType::Record(RecordType { - fields: vec1![InterfaceType::String, InterfaceType::F32], - }), - InterfaceType::I64, - ], - })], - } - } - } - - impl wasm::structures::Instance for Instance { - fn export(&self, export_name: &str) -> Option<&Export> { - self.exports.get(export_name) - } - - fn local_or_import( - &mut self, - index: I, - ) -> Option<&LocalImport> { - self.locals_or_imports.get(&index.index()) - } - - fn memory(&self, _index: usize) -> Option<&Memory> { - Some(&self.memory) - } - - fn wit_type(&self, index: u32) -> Option<&Type> { - self.wit_types.get(index as usize) - } - } -} diff --git a/lib/interface-types/src/interpreter/instructions/numbers.rs b/lib/interface-types/src/interpreter/instructions/numbers.rs deleted file mode 100644 index bedae26b2..000000000 --- a/lib/interface-types/src/interpreter/instructions/numbers.rs +++ /dev/null @@ -1,370 +0,0 @@ -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::Instruction, - types::InterfaceType, - values::InterfaceValue, -}; -use std::convert::TryInto; - -macro_rules! lowering_lifting { - ($instruction_function_name:ident, $instruction_name:expr, $to_variant:ident, $from_variant:ident) => { - executable_instruction!( - $instruction_function_name(instruction: Instruction) -> _ { - move |runtime| -> _ { - match runtime.stack.pop1() { - 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 - }, - ) - }, - )?)) - } - - Some(wrong_value) => { - return Err(InstructionError::new( - instruction, - InstructionErrorKind::InvalidValueOnTheStack { - expected_type: InterfaceType::$from_variant, - received_type: (&wrong_value).into(), - } - )) - }, - - None => { - return Err(InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { needed: 1 }, - )) - } - } - - Ok(()) - } - } - ); - }; -} - -lowering_lifting!(s8_from_i32, "s8.from_i32", S8, I32); -lowering_lifting!(s8_from_i64, "s8.from_i64", S8, I64); -lowering_lifting!(s16_from_i32, "s16.from_i32", S16, I32); -lowering_lifting!(s16_from_i64, "s16.from_i64", S16, I64); -lowering_lifting!(s32_from_i32, "s32.from_i32", S32, I32); -lowering_lifting!(s32_from_i64, "s32.from_i64", S32, I64); -lowering_lifting!(s64_from_i32, "s64.from_i32", S64, I32); -lowering_lifting!(s64_from_i64, "s64.from_i64", S64, I64); -lowering_lifting!(i32_from_s8, "i32.from_s8", I32, S8); -lowering_lifting!(i32_from_s16, "i32.from_s16", I32, S16); -lowering_lifting!(i32_from_s32, "i32.from_s32", I32, S32); -lowering_lifting!(i32_from_s64, "i32.from_s64", I32, S64); -lowering_lifting!(i64_from_s8, "i64.from_s8", I64, S8); -lowering_lifting!(i64_from_s16, "i64.from_s16", I64, S16); -lowering_lifting!(i64_from_s32, "i64.from_s32", I64, S32); -lowering_lifting!(i64_from_s64, "i64.from_s64", I64, S64); -lowering_lifting!(u8_from_i32, "u8.from_i32", U8, I32); -lowering_lifting!(u8_from_i64, "u8.from_i64", U8, I64); -lowering_lifting!(u16_from_i32, "u16.from_i32", U16, I32); -lowering_lifting!(u16_from_i64, "u16.from_i64", U16, I64); -lowering_lifting!(u32_from_i32, "u32.from_i32", U32, I32); -lowering_lifting!(u32_from_i64, "u32.from_i64", U32, I64); -lowering_lifting!(u64_from_i32, "u64.from_i32", U64, I32); -lowering_lifting!(u64_from_i64, "u64.from_i64", U64, I64); -lowering_lifting!(i32_from_u8, "i32.from_u8", I32, U8); -lowering_lifting!(i32_from_u16, "i32.from_u16", I32, U16); -lowering_lifting!(i32_from_u32, "i32.from_u32", I32, U32); -lowering_lifting!(i32_from_u64, "i32.from_u64", I32, U64); -lowering_lifting!(i64_from_u8, "i64.from_u8", I64, U8); -lowering_lifting!(i64_from_u16, "i64.from_u16", I64, U16); -lowering_lifting!(i64_from_u32, "i64.from_u32", I64, U32); -lowering_lifting!(i64_from_u64, "i64.from_u64", I64, U64); - -#[cfg(test)] -mod tests { - test_executable_instruction!( - test_convert_fails = - instructions: [Instruction::ArgumentGet { index: 0}, Instruction::S8FromI32], - invocation_inputs: [InterfaceValue::I32(128)], - instance: Instance::new(), - error: "`s8.from_i32` failed to cast `I32` to `S8`" - ); - - test_executable_instruction!( - test_type_mismatch = - instructions: [Instruction::ArgumentGet { index: 0}, Instruction::S8FromI32], - invocation_inputs: [InterfaceValue::I64(42)], - instance: Instance::new(), - error: "`s8.from_i32` read a value of type `I64` from the stack, but the type `I32` was expected" - ); - - test_executable_instruction!( - test_no_value_on_the_stack = - instructions: [Instruction::S8FromI32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - error: "`s8.from_i32` needed to read `1` value(s) from the stack, but it doesn't contain enough data" - ); - - test_executable_instruction!( - test_s8_from_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8FromI32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::S8(42)], - ); - - test_executable_instruction!( - test_s8_from_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S8FromI64], - invocation_inputs: [InterfaceValue::I64(42)], - instance: Instance::new(), - stack: [InterfaceValue::S8(42)], - ); - - test_executable_instruction!( - test_s16_from_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16FromI32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::S16(42)], - ); - - test_executable_instruction!( - test_s16_from_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S16FromI64], - invocation_inputs: [InterfaceValue::I64(42)], - instance: Instance::new(), - stack: [InterfaceValue::S16(42)], - ); - - test_executable_instruction!( - test_s32_from_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32FromI32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::S32(42)], - ); - - test_executable_instruction!( - test_s32_from_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S32FromI64], - invocation_inputs: [InterfaceValue::I64(42)], - instance: Instance::new(), - stack: [InterfaceValue::S32(42)], - ); - - test_executable_instruction!( - test_s64_from_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64FromI32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::S64(42)], - ); - - test_executable_instruction!( - test_s64_from_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::S64FromI64], - invocation_inputs: [InterfaceValue::I64(42)], - instance: Instance::new(), - stack: [InterfaceValue::S64(42)], - ); - - test_executable_instruction!( - test_i32_from_s8 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS8], - invocation_inputs: [InterfaceValue::S8(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_i32_from_s16 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS16], - invocation_inputs: [InterfaceValue::S16(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_i32_from_s32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS32], - invocation_inputs: [InterfaceValue::S32(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_i32_from_s64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromS64], - invocation_inputs: [InterfaceValue::S64(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_i64_from_s8 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS8], - invocation_inputs: [InterfaceValue::S8(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_i64_from_s16 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS16], - invocation_inputs: [InterfaceValue::S16(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_i64_from_s32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS32], - invocation_inputs: [InterfaceValue::S32(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_i64_from_s64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromS64], - invocation_inputs: [InterfaceValue::S64(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_u8_from_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8FromI32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::U8(42)], - ); - - test_executable_instruction!( - test_u8_from_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U8FromI64], - invocation_inputs: [InterfaceValue::I64(42)], - instance: Instance::new(), - stack: [InterfaceValue::U8(42)], - ); - - test_executable_instruction!( - test_u16_from_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16FromI32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::U16(42)], - ); - - test_executable_instruction!( - test_u16_from_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U16FromI64], - invocation_inputs: [InterfaceValue::I64(42)], - instance: Instance::new(), - stack: [InterfaceValue::U16(42)], - ); - - test_executable_instruction!( - test_u32_from_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32FromI32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::U32(42)], - ); - - test_executable_instruction!( - test_u32_from_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U32FromI64], - invocation_inputs: [InterfaceValue::I64(42)], - instance: Instance::new(), - stack: [InterfaceValue::U32(42)], - ); - - test_executable_instruction!( - test_u64_from_i32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64FromI32], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - stack: [InterfaceValue::U64(42)], - ); - - test_executable_instruction!( - test_u64_from_i64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::U64FromI64], - invocation_inputs: [InterfaceValue::I64(42)], - instance: Instance::new(), - stack: [InterfaceValue::U64(42)], - ); - - test_executable_instruction!( - test_i32_from_u8 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU8], - invocation_inputs: [InterfaceValue::U8(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_i32_from_u16 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU16], - invocation_inputs: [InterfaceValue::U16(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_i32_from_u32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU32], - invocation_inputs: [InterfaceValue::U32(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_i32_from_u64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I32FromU64], - invocation_inputs: [InterfaceValue::U64(42)], - instance: Instance::new(), - stack: [InterfaceValue::I32(42)], - ); - - test_executable_instruction!( - test_i64_from_u8 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU8], - invocation_inputs: [InterfaceValue::U8(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_i64_from_u16 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU16], - invocation_inputs: [InterfaceValue::U16(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_i64_from_u32 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU32], - invocation_inputs: [InterfaceValue::U32(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); - - test_executable_instruction!( - test_i64_from_u64 = - instructions: [Instruction::ArgumentGet { index: 0 }, Instruction::I64FromU64], - invocation_inputs: [InterfaceValue::U64(42)], - instance: Instance::new(), - stack: [InterfaceValue::I64(42)], - ); -} diff --git a/lib/interface-types/src/interpreter/instructions/records.rs b/lib/interface-types/src/interpreter/instructions/records.rs deleted file mode 100644 index e63dbf882..000000000 --- a/lib/interface-types/src/interpreter/instructions/records.rs +++ /dev/null @@ -1,384 +0,0 @@ -use crate::{ - ast::{Type, TypeKind}, - errors::{InstructionError, InstructionErrorKind}, - interpreter::{ - stack::{Stack, Stackable}, - Instruction, - }, - types::{InterfaceType, RecordType}, - values::{FlattenInterfaceValueIterator, InterfaceValue}, - vec1::Vec1, -}; -use std::collections::VecDeque; - -/// Build an `InterfaceValue::Record` based on values on the stack. -/// -/// To fill a record, every field `field_1` to `field_n` must get its -/// value from the stack with `value_1` to `value_n`. It is not -/// possible to use `Stack::pop` because the one-pass algorithm does -/// not know exactly the number of values to read from the stack -/// ahead-of-time, so `Stack::pop1` is used. It implies that values -/// are read one after the other from the stack, in a natural reverse -/// order, from `value_n` to `value_1`. Thus, the `values` vector must -/// be filled from the end to the beginning. It is not safely possible -/// to fill the `values` vector with empty values though (so that it -/// is possible to access to last positions). So a `VecDeque` type is -/// used: it is a double-ended queue. -fn record_lift_( - stack: &mut Stack, - record_type: &RecordType, -) -> Result { - let length = record_type.fields.len(); - let mut values = VecDeque::with_capacity(length); - - // Iterate over fields in reverse order to match the stack `pop` - // order. - for field in record_type.fields.iter().rev() { - match field { - // The record type tells a record is expected. - InterfaceType::Record(record_type) => { - // Build it recursively. - values.push_front(record_lift_(stack, &record_type)?) - } - // Any other type. - ty => { - let value = stack.pop1().unwrap(); - let value_type = (&value).into(); - - if ty != &value_type { - return Err(InstructionErrorKind::InvalidValueOnTheStack { - expected_type: ty.clone(), - received_type: value_type, - }); - } - - values.push_front(value) - } - } - } - - Ok(InterfaceValue::Record( - Vec1::new(values.into_iter().collect()) - .expect("Record must have at least one field, zero given"), // normally unreachable because of the type-checking - )) -} - -executable_instruction!( - record_lift(type_index: u32, instruction: Instruction) -> _ { - move |runtime| -> _ { - let instance = &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 - } - )), - }; - - let record = record_lift_(&mut runtime.stack, &record_type) - .map_err(|k| InstructionError::new(instruction, k))?; - - runtime.stack.push(record); - - Ok(()) - } - } -); - -executable_instruction!( - record_lower(type_index: u32, instruction: Instruction) -> _ { - move |runtime| -> _ { - let instance = &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 values = FlattenInterfaceValueIterator::new(&record_values); - - for value in values { - runtime.stack.push(value.clone()); - } - - Ok(()) - }, - - Some(value) => Err(InstructionError::new( - instruction, - InstructionErrorKind::InvalidValueOnTheStack { - expected_type: InterfaceType::Record(record_type.clone()), - received_type: (&value).into(), - } - )), - - None => Err(InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { needed: 1 }, - )), - } - } - } -); - -#[cfg(test)] -mod tests { - use super::*; - - test_executable_instruction!( - test_record_lift = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::ArgumentGet { index: 2 }, - Instruction::ArgumentGet { index: 3 }, - Instruction::RecordLift { type_index: 0 }, - ], - invocation_inputs: [ - InterfaceValue::I32(1), - InterfaceValue::String("Hello".to_string()), - InterfaceValue::F32(2.), - InterfaceValue::I64(3), - ], - instance: Instance::new(), - stack: [InterfaceValue::Record(vec1![ - InterfaceValue::I32(1), - InterfaceValue::Record(vec1![ - InterfaceValue::String("Hello".to_string()), - InterfaceValue::F32(2.), - ]), - InterfaceValue::I64(3), - ])], - ); - - #[cfg(feature = "serde")] - #[test] - #[allow(non_snake_case, unused)] - fn test_record_lift__to_rust_struct() { - use crate::{ - interpreter::{ - instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView}, - stack::Stackable, - Instruction, Interpreter, - }, - types::InterfaceType, - values::{from_interface_values, InterfaceValue}, - }; - use serde::Deserialize; - use std::{cell::Cell, collections::HashMap, convert::TryInto}; - - let interpreter: Interpreter = (&vec![ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::ArgumentGet { index: 2 }, - Instruction::ArgumentGet { index: 3 }, - Instruction::RecordLift { type_index: 0 }, - ]) - .try_into() - .unwrap(); - - let invocation_inputs = vec![ - InterfaceValue::I32(1), - InterfaceValue::String("Hello".to_string()), - InterfaceValue::F32(2.), - InterfaceValue::I64(3), - ]; - let mut instance = Instance::new(); - let run = interpreter.run(&invocation_inputs, &mut instance); - - assert!(run.is_ok()); - - let stack = run.unwrap(); - - #[derive(Deserialize, Debug, PartialEq)] - struct S { - a: String, - b: f32, - } - - #[derive(Deserialize, Debug, PartialEq)] - struct T { - x: i32, - s: S, - y: i64, - } - - let record: T = from_interface_values(stack.as_slice()).unwrap(); - - assert_eq!( - record, - T { - x: 1, - s: S { - a: "Hello".to_string(), - b: 2., - }, - y: 3, - } - ); - } - - test_executable_instruction!( - test_record_lift__one_dimension = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::RecordLift { type_index: 1 }, - ], - invocation_inputs: [ - InterfaceValue::I32(1), - InterfaceValue::I32(2), - ], - instance: { - let mut instance = Instance::new(); - instance.wit_types.push( - Type::Record(RecordType { - fields: vec1![InterfaceType::I32, InterfaceType::I32], - }) - ); - - instance - }, - stack: [InterfaceValue::Record(vec1![ - InterfaceValue::I32(1), - InterfaceValue::I32(2), - ])], - ); - - test_executable_instruction!( - test_record_lift__type_is_missing = - instructions: [ - Instruction::RecordLift { type_index: 0 }, - ], - invocation_inputs: [], - instance: Default::default(), - error: r#"`record.lift 0` the type `0` doesn't exist"#, - ); - - test_executable_instruction!( - test_record_lift__invalid_value_on_the_stack = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::ArgumentGet { index: 2 }, - Instruction::ArgumentGet { index: 3 }, - Instruction::RecordLift { type_index: 0 }, - ], - invocation_inputs: [ - InterfaceValue::I32(1), - InterfaceValue::String("Hello".to_string()), - InterfaceValue::F64(2.), - // ^^^ F32 is expected - InterfaceValue::I64(3), - ], - instance: Instance::new(), - error: r#"`record.lift 0` read a value of type `F64` from the stack, but the type `F32` was expected"#, - ); - - test_executable_instruction!( - test_record_lower = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::RecordLower { type_index: 0 }, - ], - invocation_inputs: [ - InterfaceValue::Record(vec1![ - InterfaceValue::I32(1), - InterfaceValue::Record(vec1![ - InterfaceValue::String("Hello".to_string()), - InterfaceValue::F32(2.), - ]), - InterfaceValue::I64(3), - ]) - ], - instance: Instance::new(), - stack: [ - InterfaceValue::I32(1), - InterfaceValue::String("Hello".to_string()), - InterfaceValue::F32(2.), - InterfaceValue::I64(3), - ], - ); - - test_executable_instruction!( - test_record__roundtrip = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::RecordLower { type_index: 0 }, - Instruction::RecordLift { type_index: 0 }, - ], - invocation_inputs: [ - InterfaceValue::Record(vec1![ - InterfaceValue::I32(1), - InterfaceValue::Record(vec1![ - InterfaceValue::String("Hello".to_string()), - InterfaceValue::F32(2.), - ]), - InterfaceValue::I64(3), - ]) - ], - instance: Instance::new(), - stack: [ - InterfaceValue::Record(vec1![ - InterfaceValue::I32(1), - InterfaceValue::Record(vec1![ - InterfaceValue::String("Hello".to_string()), - InterfaceValue::F32(2.), - ]), - InterfaceValue::I64(3), - ]) - ], - ); - - test_executable_instruction!( - test_record_lower__invalid_value_on_the_stack = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::RecordLower { type_index: 0 }, - ], - invocation_inputs: [ - InterfaceValue::I32(1), - ], - instance: Instance::new(), - error: r#"`record.lower 0` read a value of type `I32` from the stack, but the type `Record(RecordType { fields: [I32, Record(RecordType { fields: [String, F32] }), I64] })` was expected"#, - ); - - test_executable_instruction!( - test_record_lower__invalid_value_on_the_stack__different_record_type = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::RecordLower { type_index: 0 }, - ], - invocation_inputs: [ - InterfaceValue::Record(vec1![ - InterfaceValue::I32(1), - InterfaceValue::Record(vec1![ - InterfaceValue::String("Hello".to_string()), - ]), - InterfaceValue::I64(3), - ]) - ], - instance: Instance::new(), - error: r#"`record.lower 0` read a value of type `Record(RecordType { fields: [I32, Record(RecordType { fields: [String] }), I64] })` from the stack, but the type `Record(RecordType { fields: [I32, Record(RecordType { fields: [String, F32] }), I64] })` was expected"#, - ); -} diff --git a/lib/interface-types/src/interpreter/instructions/strings.rs b/lib/interface-types/src/interpreter/instructions/strings.rs deleted file mode 100644 index 854728fc6..000000000 --- a/lib/interface-types/src/interpreter/instructions/strings.rs +++ /dev/null @@ -1,354 +0,0 @@ -use super::to_native; -use crate::{ - errors::{InstructionError, InstructionErrorKind}, - interpreter::Instruction, - types::InterfaceType, - values::InterfaceValue, -}; -use std::{cell::Cell, convert::TryInto}; - -executable_instruction!( - string_lift_memory(instruction: Instruction) -> _ { - move |runtime| -> _ { - let inputs = runtime.stack.pop(2).ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { needed: 2 }, - ) - })?; - - let memory_index: u32 = 0; - let memory = runtime - .wasm_instance - .memory(memory_index as usize) - .ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::MemoryIsMissing { memory_index }, - ) - })?; - - let pointer: usize = to_native::(&inputs[0], instruction)? - .try_into() - .map_err(|e| (e, "pointer").into()) - .map_err(|k| InstructionError::new(instruction, k))?; - let length: usize = to_native::(&inputs[1], instruction)? - .try_into() - .map_err(|e| (e, "length").into()) - .map_err(|k| InstructionError::new(instruction, k))?; - let memory_view = memory.view(); - - if length == 0 { - runtime.stack.push(InterfaceValue::String("".into())); - - return Ok(()) - } - - if memory_view.len() <= pointer + length - 1 { - return Err(InstructionError::new( - instruction, - InstructionErrorKind::MemoryOutOfBoundsAccess { - index: pointer + length, - length: memory_view.len(), - }, - )); - } - - let data: Vec = (&memory_view[pointer..=pointer + length - 1]) - .iter() - .map(Cell::get) - .collect(); - - let string = String::from_utf8(data) - .map_err(|error| InstructionError::new(instruction, InstructionErrorKind::String(error)))?; - - runtime.stack.push(InterfaceValue::String(string)); - - Ok(()) - } - } -); - -executable_instruction!( - string_lower_memory(instruction: Instruction) -> _ { - move |runtime| -> _ { - let inputs = runtime.stack.pop(2).ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { needed: 2 }, - ) - })?; - - let string_pointer: usize = to_native::(&inputs[0], instruction)? - .try_into() - .map_err(|e| (e, "pointer").into()) - .map_err(|k| InstructionError::new(instruction, k))?; - let string: String = to_native(&inputs[1], instruction)?; - let string_bytes = string.as_bytes(); - let string_length: i32 = string_bytes.len().try_into().map_err(|_| { - InstructionError::new( - instruction, - InstructionErrorKind::NegativeValue { subject: "string_length" }, - ) - })?; - - let instance = &mut runtime.wasm_instance; - let memory_index: u32 = 0; - let memory_view = instance - .memory(memory_index as usize) - .ok_or_else(|| { - InstructionError::new( - instruction, - InstructionErrorKind::MemoryIsMissing { memory_index }, - ) - })? - .view(); - - for (nth, byte) in string_bytes.iter().enumerate() { - memory_view[string_pointer as usize + nth].set(*byte); - } - - runtime.stack.push(InterfaceValue::I32(string_pointer as i32)); - runtime.stack.push(InterfaceValue::I32(string_length)); - - Ok(()) - } - } -); - -executable_instruction!( - string_size(instruction: Instruction) -> _ { - move |runtime| -> _ { - match runtime.stack.pop1() { - Some(InterfaceValue::String(string)) => { - let length = string.len() as i32; - runtime.stack.push(InterfaceValue::I32(length)); - - Ok(()) - }, - - Some(value) => Err(InstructionError::new( - instruction, - InstructionErrorKind::InvalidValueOnTheStack { - expected_type: InterfaceType::String, - received_type: (&value).into(), - }, - )), - - None => Err(InstructionError::new( - instruction, - InstructionErrorKind::StackIsTooSmall { needed: 1 }, - )), - } - } - } -); - -#[cfg(test)] -mod tests { - test_executable_instruction!( - test_string_lift_memory = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::StringLiftMemory, - ], - invocation_inputs: [ - InterfaceValue::I32(0), - // ^^^^^^ pointer - InterfaceValue::I32(13), - // ^^^^^^^ length - ], - instance: Instance { - memory: Memory::new("Hello, World!".as_bytes().iter().map(|u| Cell::new(*u)).collect()), - ..Default::default() - }, - stack: [InterfaceValue::String("Hello, World!".into())], - ); - - test_executable_instruction!( - test_string_lift_memory__empty_string = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::StringLiftMemory, - ], - invocation_inputs: [ - InterfaceValue::I32(0), - InterfaceValue::I32(0), - ], - instance: Instance { - memory: Memory::new(vec![]), - ..Default::default() - }, - stack: [InterfaceValue::String("".into())], - ); - - test_executable_instruction!( - test_string_lift_memory__negative_pointer = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::StringLiftMemory, - ], - invocation_inputs: [ - InterfaceValue::I32(-42), - InterfaceValue::I32(13), - ], - instance: Instance { - memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()), - ..Default::default() - }, - error: r#"`string.lift_memory` attempted to convert `pointer` but it appears to be a negative value"#, - ); - - test_executable_instruction!( - test_string_lift_memory__negative_length = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::StringLiftMemory, - ], - invocation_inputs: [ - InterfaceValue::I32(0), - InterfaceValue::I32(-1), - ], - instance: Instance { - memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()), - ..Default::default() - }, - error: r#"`string.lift_memory` attempted to convert `length` but it appears to be a negative value"#, - ); - - test_executable_instruction!( - test_string_lift_memory__read_out_of_memory = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::StringLiftMemory, - ], - invocation_inputs: [ - InterfaceValue::I32(0), - // ^^^^^^ pointer - InterfaceValue::I32(13), - // ^^^^^^^ length is too long - ], - instance: Instance { - memory: Memory::new("Hello!".as_bytes().iter().map(|u| Cell::new(*u)).collect()), - ..Default::default() - }, - error: r#"`string.lift_memory` read out of the memory bounds (index 13 > memory length 6)"#, - ); - - test_executable_instruction!( - test_string_lift_memory__invalid_encoding = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::ArgumentGet { index: 1 }, - Instruction::StringLiftMemory, - ], - invocation_inputs: [ - InterfaceValue::I32(0), - // ^^^^^^ pointer - InterfaceValue::I32(4), - // ^^^^^^ length is too long - ], - instance: Instance { - memory: Memory::new(vec![0, 159, 146, 150].iter().map(|b| Cell::new(*b)).collect::>>()), - ..Default::default() - }, - error: r#"`string.lift_memory` invalid utf-8 sequence of 1 bytes from index 1"#, - ); - - test_executable_instruction!( - test_string_lift_memory__stack_is_too_small = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::StringLiftMemory, - // ^^^^^^^^^^^^^^^^ `string.lift_memory` expects 2 values on the stack, only one is present. - ], - invocation_inputs: [ - InterfaceValue::I32(0), - InterfaceValue::I32(13), - ], - instance: Instance::new(), - error: r#"`string.lift_memory` needed to read `2` value(s) from the stack, but it doesn't contain enough data"#, - ); - - test_executable_instruction!( - test_string_lower_memory = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::StringSize, - Instruction::CallCore { function_index: 43 }, - Instruction::ArgumentGet { index: 0 }, - Instruction::StringLowerMemory, - - ], - invocation_inputs: [InterfaceValue::String("Hello, World!".into())], - instance: Instance::new(), - stack: [ - InterfaceValue::I32(0), - // ^^^^^^ pointer - InterfaceValue::I32(13), - // ^^^^^^^ length - ] - ); - - test_executable_instruction!( - test_string__roundtrip = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::StringSize, - Instruction::CallCore { function_index: 43 }, - Instruction::ArgumentGet { index: 0 }, - Instruction::StringLowerMemory, - Instruction::StringLiftMemory, - ], - invocation_inputs: [InterfaceValue::String("Hello, World!".into())], - instance: Instance::new(), - stack: [InterfaceValue::String("Hello, World!".into())], - ); - - test_executable_instruction!( - test_string_lower_memory__stack_is_too_small = - instructions: [ - Instruction::StringLowerMemory, - ], - invocation_inputs: [], - instance: Instance::new(), - error: r#"`string.lower_memory` needed to read `2` value(s) from the stack, but it doesn't contain enough data"#, - ); - - test_executable_instruction!( - test_string_size = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::StringSize, - ], - invocation_inputs: [InterfaceValue::String("Hello, World!".into())], - instance: Instance::new(), - stack: [InterfaceValue::I32(13)], - ); - - test_executable_instruction!( - test_string_size__stack_is_too_small = - instructions: [ - Instruction::StringSize, - ], - invocation_inputs: [], - instance: Instance::new(), - error: r#"`string.size` needed to read `1` value(s) from the stack, but it doesn't contain enough data"#, - ); - - test_executable_instruction!( - test_string_size__invalid_value_on_the_stack = - instructions: [ - Instruction::ArgumentGet { index: 0 }, - Instruction::StringSize, - ], - invocation_inputs: [InterfaceValue::I32(42)], - instance: Instance::new(), - error: r#"`string.size` read a value of type `I32` from the stack, but the type `String` was expected"#, - ); -} diff --git a/lib/interface-types/src/interpreter/mod.rs b/lib/interface-types/src/interpreter/mod.rs deleted file mode 100644 index e7d93cef2..000000000 --- a/lib/interface-types/src/interpreter/mod.rs +++ /dev/null @@ -1,254 +0,0 @@ -//! A stack-based interpreter to execute instructions of WIT adapters. - -mod instructions; -pub mod stack; -pub mod wasm; - -use crate::{ - errors::{InstructionResult, InterpreterResult}, - values::InterfaceValue, -}; -pub use instructions::Instruction; -use stack::Stack; -use std::{convert::TryFrom, marker::PhantomData}; - -/// Represents the `Runtime`, which is used by an adapter to execute -/// its instructions. -pub(crate) struct Runtime<'invocation, 'instance, Instance, Export, LocalImport, Memory, MemoryView> -where - Export: wasm::structures::Export + 'instance, - LocalImport: wasm::structures::LocalImport + 'instance, - Memory: wasm::structures::Memory + 'instance, - MemoryView: wasm::structures::MemoryView, - Instance: wasm::structures::Instance + 'instance, -{ - /// The invocation inputs are all the arguments received by an - /// adapter. - invocation_inputs: &'invocation [InterfaceValue], - - /// Each runtime (so adapter) has its own stack instance. - stack: Stack, - - /// The WebAssembly module instance. It is used by adapter's - /// instructions. - wasm_instance: &'instance mut Instance, - - /// Phantom data. - _phantom: PhantomData<(Export, LocalImport, Memory, MemoryView)>, -} - -/// Type alias for an executable instruction. It's an implementation -/// details, but an instruction is a boxed closure instance. -pub(crate) type ExecutableInstruction = Box< - dyn Fn( - &mut Runtime, - ) -> InstructionResult<()>, ->; - -/// An interpreter is the central piece of this crate. It is a set of -/// executable instructions. Each instruction takes the runtime as -/// argument. The runtime holds the invocation inputs, [the -/// stack](stack), and [the WebAssembly instance](wasm). -/// -/// When the interpreter executes the instructions, each of them can -/// query the WebAssembly instance, operates on the stack, or reads -/// the invocation inputs. At the end of the execution, the stack -/// supposedly contains a result. Since an interpreter is used by a -/// WIT adapter to execute its instructions, the result on the stack -/// is the result of the adapter. -/// -/// # Example -/// -/// ```rust,ignore -/// use std::{cell::Cell, collections::HashMap, convert::TryInto}; -/// use wasmer_interface_types::{ -/// interpreter::{ -/// instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView}, -/// // ^^^^^^^^^^^^ This is private and for testing purposes only. -/// // It is basically a fake WebAssembly runtime. -/// stack::Stackable, -/// Instruction, Interpreter, -/// }, -/// types::InterfaceType, -/// values::InterfaceValue, -/// }; -/// -/// // 1. Creates an interpreter from a set of instructions. They will -/// // be transformed into executable instructions. -/// let interpreter: Interpreter = (&vec![ -/// Instruction::ArgumentGet { index: 1 }, -/// Instruction::ArgumentGet { index: 0 }, -/// Instruction::CallCore { function_index: 42 }, -/// ]) -/// .try_into() -/// .unwrap(); -/// -/// // 2. Defines the arguments of the adapter. -/// let invocation_inputs = vec![InterfaceValue::I32(3), InterfaceValue::I32(4)]; -/// -/// // 3. Creates a WebAssembly instance. -/// let mut instance = Instance { -/// // 3.1. Defines one function: `fn sum(a: i32, b: i32) -> i32 { a + b }`. -/// locals_or_imports: { -/// let mut hashmap = HashMap::new(); -/// hashmap.insert( -/// 42, -/// LocalImport { -/// // Defines the argument types of the function. -/// inputs: vec![InterfaceType::I32, InterfaceType::I32], -/// -/// // Defines the result types. -/// outputs: vec![InterfaceType::I32], -/// -/// // Defines the function implementation. -/// function: |arguments: &[InterfaceValue]| { -/// let a: i32 = (&arguments[0]).try_into().unwrap(); -/// let b: i32 = (&arguments[1]).try_into().unwrap(); -/// -/// Ok(vec![InterfaceValue::I32(a + b)]) -/// }, -/// }, -/// ); -/// }, -/// ..Default::default() -/// }; -/// -/// // 4. Executes the instructions. -/// let run = interpreter.run(&invocation_inputs, &mut instance); -/// -/// assert!(run.is_ok()); -/// -/// let stack = run.unwrap(); -/// -/// // 5. Read the stack to get the result. -/// assert_eq!(stack.as_slice(), &[InterfaceValue::I32(7)]); -/// ``` -pub struct Interpreter -where - Export: wasm::structures::Export, - LocalImport: wasm::structures::LocalImport, - Memory: wasm::structures::Memory, - MemoryView: wasm::structures::MemoryView, - Instance: wasm::structures::Instance, -{ - executable_instructions: - Vec>, -} - -impl - Interpreter -where - Export: wasm::structures::Export, - LocalImport: wasm::structures::LocalImport, - Memory: wasm::structures::Memory, - MemoryView: wasm::structures::MemoryView, - Instance: wasm::structures::Instance, -{ - fn iter( - &self, - ) -> impl Iterator< - Item = &ExecutableInstruction, - > + '_ { - self.executable_instructions.iter() - } - - /// Runs the interpreter, such as: - /// 1. Create a fresh stack, - /// 2. Create a fresh stack, - /// 3. Execute the instructions one after the other, and - /// returns the stack. - pub fn run( - &self, - invocation_inputs: &[InterfaceValue], - wasm_instance: &mut Instance, - ) -> InterpreterResult> { - let mut runtime = Runtime { - invocation_inputs, - stack: Stack::new(), - wasm_instance, - _phantom: PhantomData, - }; - - for executable_instruction in self.iter() { - executable_instruction(&mut runtime)?; - } - - Ok(runtime.stack) - } -} - -/// Transforms a `Vec` into an `Interpreter`. -impl TryFrom<&Vec> - for Interpreter -where - Export: wasm::structures::Export, - LocalImport: wasm::structures::LocalImport, - Memory: wasm::structures::Memory, - MemoryView: wasm::structures::MemoryView, - Instance: wasm::structures::Instance, -{ - type Error = (); - - fn try_from(instructions: &Vec) -> Result { - let executable_instructions = instructions - .iter() - .map(|instruction| match instruction { - Instruction::ArgumentGet { index } => { - instructions::argument_get(*index, *instruction) - } - - Instruction::CallCore { function_index } => { - instructions::call_core(*function_index, *instruction) - } - - Instruction::S8FromI32 => instructions::s8_from_i32(*instruction), - Instruction::S8FromI64 => instructions::s8_from_i64(*instruction), - Instruction::S16FromI32 => instructions::s16_from_i32(*instruction), - Instruction::S16FromI64 => instructions::s16_from_i64(*instruction), - Instruction::S32FromI32 => instructions::s32_from_i32(*instruction), - Instruction::S32FromI64 => instructions::s32_from_i64(*instruction), - Instruction::S64FromI32 => instructions::s64_from_i32(*instruction), - Instruction::S64FromI64 => instructions::s64_from_i64(*instruction), - Instruction::I32FromS8 => instructions::i32_from_s8(*instruction), - Instruction::I32FromS16 => instructions::i32_from_s16(*instruction), - Instruction::I32FromS32 => instructions::i32_from_s32(*instruction), - Instruction::I32FromS64 => instructions::i32_from_s64(*instruction), - Instruction::I64FromS8 => instructions::i64_from_s8(*instruction), - Instruction::I64FromS16 => instructions::i64_from_s16(*instruction), - Instruction::I64FromS32 => instructions::i64_from_s32(*instruction), - Instruction::I64FromS64 => instructions::i64_from_s64(*instruction), - Instruction::U8FromI32 => instructions::u8_from_i32(*instruction), - Instruction::U8FromI64 => instructions::u8_from_i64(*instruction), - Instruction::U16FromI32 => instructions::u16_from_i32(*instruction), - Instruction::U16FromI64 => instructions::u16_from_i64(*instruction), - Instruction::U32FromI32 => instructions::u32_from_i32(*instruction), - Instruction::U32FromI64 => instructions::u32_from_i64(*instruction), - Instruction::U64FromI32 => instructions::u64_from_i32(*instruction), - Instruction::U64FromI64 => instructions::u64_from_i64(*instruction), - Instruction::I32FromU8 => instructions::i32_from_u8(*instruction), - Instruction::I32FromU16 => instructions::i32_from_u16(*instruction), - Instruction::I32FromU32 => instructions::i32_from_u32(*instruction), - Instruction::I32FromU64 => instructions::i32_from_u64(*instruction), - Instruction::I64FromU8 => instructions::i64_from_u8(*instruction), - Instruction::I64FromU16 => instructions::i64_from_u16(*instruction), - Instruction::I64FromU32 => instructions::i64_from_u32(*instruction), - Instruction::I64FromU64 => instructions::i64_from_u64(*instruction), - - Instruction::StringLiftMemory => instructions::string_lift_memory(*instruction), - Instruction::StringLowerMemory => instructions::string_lower_memory(*instruction), - Instruction::StringSize => instructions::string_size(*instruction), - - Instruction::RecordLift { type_index } => { - instructions::record_lift(*type_index, *instruction) - } - Instruction::RecordLower { type_index } => { - instructions::record_lower(*type_index, *instruction) - } - }) - .collect(); - - Ok(Interpreter { - executable_instructions, - }) - } -} diff --git a/lib/interface-types/src/interpreter/stack.rs b/lib/interface-types/src/interpreter/stack.rs deleted file mode 100644 index 321fcf4d2..000000000 --- a/lib/interface-types/src/interpreter/stack.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! A very light and generic stack implementation, exposing only the -//! operations required by the interpreter. - -/// The `Stackable` trait represents a small basic set of operations -/// required by the interpreter. -pub trait Stackable { - /// The kind of item the stack holds. - type Item; - - /// Checks whether the stack is empty. - fn is_empty(&self) -> bool; - - /// Extracts a slice containing the entire stack. - fn as_slice(&self) -> &[Self::Item]; - - /// Appends one item to the end of the stack. - fn push(&mut self, item: Self::Item); - - /// Removes the last item of the stack and returns it, `None` if - /// the stack is empty. - fn pop1(&mut self) -> Option; - - /// Removes `n` elements from the end of the stack, `None` if the - /// stack doesn't contain enough elements. - /// Returned items are in reverse order: the last element comes - /// last in the list. - fn pop(&mut self, n: usize) -> Option>; - - /// Peek the last item of the stack and returns a reference to it, - /// `None` if the stack is empty. - fn peek1(&self) -> Option<&Self::Item>; -} - -/// A stack implementation of the `Stackable` trait, based on a vector. -#[derive(Debug, Default)] -pub struct Stack -where - T: Default + Clone, -{ - /// Inner structure holding the items. - inner: Vec, -} - -impl Stack -where - T: Default + Clone, -{ - /// Creates a new empty stack. - pub fn new() -> Self { - Self { - ..Default::default() - } - } -} - -impl Stackable for Stack -where - T: Default + Clone, -{ - type Item = T; - - fn is_empty(&self) -> bool { - self.inner.is_empty() - } - - fn as_slice(&self) -> &[Self::Item] { - self.inner.as_slice() - } - - fn push(&mut self, item: Self::Item) { - self.inner.push(item); - } - - fn pop1(&mut self) -> Option { - self.inner.pop() - } - - fn pop(&mut self, n: usize) -> Option> { - if self.inner.len() < n { - None - } else { - let items = self - .inner - .drain(self.inner.len() - n..) - .collect::>(); - - assert!(items.len() == n); - - Some(items) - } - } - - fn peek1(&self) -> Option<&Self::Item> { - if self.inner.is_empty() { - None - } else { - Some(&self.inner[self.inner.len() - 1]) - } - } -} - -#[cfg(test)] -mod tests { - use super::{Stack, Stackable}; - - #[test] - fn test_is_empty() { - let mut stack = Stack::new(); - assert_eq!(stack.is_empty(), true); - - stack.push(1); - assert_eq!(stack.is_empty(), false); - } - - #[test] - fn test_push_pop1() { - let mut stack = Stack::new(); - stack.push(1); - - assert_eq!(stack.pop1(), Some(1)); - assert_eq!(stack.is_empty(), true); - } - - #[test] - fn test_pop() { - let mut stack = Stack::new(); - stack.push(1); - stack.push(2); - stack.push(3); - stack.push(4); - stack.push(5); - stack.push(6); - - assert_eq!(stack.pop(1), Some(vec![6])); - assert_eq!(stack.pop(2), Some(vec![4, 5])); - assert_eq!(stack.pop(4), None); // not enough items - assert_eq!(stack.pop(3), Some(vec![1, 2, 3])); - assert_eq!(stack.pop1(), None); - assert_eq!(stack.is_empty(), true); - } - - #[test] - fn test_peek1() { - let mut stack = Stack::new(); - stack.push(1); - stack.push(2); - - assert_eq!(stack.peek1(), Some(&2)); - } -} diff --git a/lib/interface-types/src/interpreter/wasm/mod.rs b/lib/interface-types/src/interpreter/wasm/mod.rs deleted file mode 100644 index a196df687..000000000 --- a/lib/interface-types/src/interpreter/wasm/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! An hypothetic WebAssembly runtime, represented as a set of enums, -//! types, and traits —basically this is the part a runtime should -//! take a look to use the `wasmer-interface-types` crate—. - -pub mod structures; diff --git a/lib/interface-types/src/interpreter/wasm/structures.rs b/lib/interface-types/src/interpreter/wasm/structures.rs deleted file mode 100644 index 217a4186f..000000000 --- a/lib/interface-types/src/interpreter/wasm/structures.rs +++ /dev/null @@ -1,164 +0,0 @@ -#![allow(missing_docs)] - -use crate::{ast, types::InterfaceType, values::InterfaceValue}; -use std::{cell::Cell, ops::Deref}; - -pub trait TypedIndex: Copy + Clone { - fn new(index: usize) -> Self; - fn index(&self) -> usize; -} - -macro_rules! typed_index { - ($type:ident) => { - #[derive(Copy, Clone)] - pub struct $type(usize); - - impl TypedIndex for $type { - fn new(index: usize) -> Self { - Self(index) - } - - fn index(&self) -> usize { - self.0 - } - } - }; -} - -typed_index!(FunctionIndex); -typed_index!(LocalFunctionIndex); -typed_index!(ImportFunctionIndex); - -pub trait LocalImportIndex { - type Local: TypedIndex; - type Import: TypedIndex; -} - -impl LocalImportIndex for FunctionIndex { - type Local = LocalFunctionIndex; - type Import = ImportFunctionIndex; -} - -pub trait Export { - fn inputs_cardinality(&self) -> usize; - fn outputs_cardinality(&self) -> usize; - fn inputs(&self) -> &[InterfaceType]; - fn outputs(&self) -> &[InterfaceType]; - fn call(&self, arguments: &[InterfaceValue]) -> Result, ()>; -} - -pub trait LocalImport { - fn inputs_cardinality(&self) -> usize; - fn outputs_cardinality(&self) -> usize; - fn inputs(&self) -> &[InterfaceType]; - fn outputs(&self) -> &[InterfaceType]; - fn call(&self, arguments: &[InterfaceValue]) -> Result, ()>; -} - -pub trait MemoryView: Deref]> {} - -pub trait Memory -where - View: MemoryView, -{ - fn view(&self) -> View; -} - -pub trait Instance -where - E: Export, - LI: LocalImport, - M: Memory, - MV: MemoryView, -{ - fn export(&self, export_name: &str) -> Option<&E>; - fn local_or_import(&mut self, index: I) -> Option<&LI>; - fn memory(&self, index: usize) -> Option<&M>; - fn wit_type(&self, index: u32) -> Option<&ast::Type>; -} - -impl Export for () { - fn inputs_cardinality(&self) -> usize { - 0 - } - - fn outputs_cardinality(&self) -> usize { - 0 - } - - fn inputs(&self) -> &[InterfaceType] { - &[] - } - - fn outputs(&self) -> &[InterfaceType] { - &[] - } - - fn call(&self, _arguments: &[InterfaceValue]) -> Result, ()> { - Err(()) - } -} - -impl LocalImport for () { - fn inputs_cardinality(&self) -> usize { - 0 - } - - fn outputs_cardinality(&self) -> usize { - 0 - } - - fn inputs(&self) -> &[InterfaceType] { - &[] - } - - fn outputs(&self) -> &[InterfaceType] { - &[] - } - - fn call(&self, _arguments: &[InterfaceValue]) -> Result, ()> { - Err(()) - } -} - -pub(crate) struct EmptyMemoryView; - -impl MemoryView for EmptyMemoryView {} - -impl Deref for EmptyMemoryView { - type Target = [Cell]; - - fn deref(&self) -> &Self::Target { - &[] - } -} - -impl Memory for () { - fn view(&self) -> EmptyMemoryView { - EmptyMemoryView - } -} - -impl Instance for () -where - E: Export, - LI: LocalImport, - M: Memory, - MV: MemoryView, -{ - fn export(&self, _export_name: &str) -> Option<&E> { - None - } - - fn memory(&self, _: usize) -> Option<&M> { - None - } - - fn local_or_import(&mut self, _index: I) -> Option<&LI> { - None - } - - fn wit_type(&self, _index: u32) -> Option<&ast::Type> { - None - } -} diff --git a/lib/interface-types/src/lib.rs b/lib/interface-types/src/lib.rs deleted file mode 100644 index d5e9ac05b..000000000 --- a/lib/interface-types/src/lib.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! This crate contains an implementation of [WebAssembly Interface -//! Types][wit] (abbreviated WIT). It is composed of 5 parts: -//! -//! 1. [Types] and [Values]: To represent the WIT types and values -//! representations, -//! 2. [AST]: To represent the WIT language as a tree -//! (which is not really abstract). This is the central -//! representation of the language. -//! 3. [Decoders](decoders): To read the [AST] from a particular data -//! representation; for instance, [`decoders::binary::parse`] reads -//! the [AST] from a binary. -//! 4. [Encoders](encoders): To write the [AST](ast) into a particular -//! format; for instance, [`encoders::wat`] writes the [AST] into a -//! string representing WIT with its textual format. -//! 5. [Interpreter](interpreter): WIT defines a concept called -//! Adapters. An adapter contains a set of [instructions]. So, in -//! more details, this module contains: -//! * [A very light and generic stack -//! implementation](interpreter::stack), exposing only the -//! operations required by the interpreter, -//! * [A stack-based interpreter](interpreter::Interpreter), -//! defined by: -//! * A compiler that transforms a set of instructions into a -//! set of executable instructions, -//! * A stack, -//! * A runtime that holds the “invocation inputs” (arguments -//! of the interpreter), the stack, and the WebAssembly -//! instance (which holds the exports, the imports, the -//! memories, the tables etc.), -//! * [An hypothetic WebAssembly runtime](interpreter::wasm), -//! represented as a set of enums, types, and traits —basically -//! this is the part a runtime should take a look to use the -//! `wasmer-interface-types` crate—. -//! -//! [wit]: https://github.com/WebAssembly/interface-types -//! [Types]: types -//! [Values]: values -//! [AST]: ast -//! [instructions]: interpreter::Instruction - -#![deny( - dead_code, - intra_doc_link_resolution_failure, - missing_docs, - nonstandard_style, - unreachable_patterns, - unused_imports, - unused_mut, - unused_unsafe, - unused_variables -)] -#![forbid(unsafe_code)] -#![doc(html_favicon_url = "https://wasmer.io/static/icons/favicon.ico")] -#![doc(html_logo_url = "https://github.com/wasmerio.png")] - -pub mod ast; -pub mod types; -#[macro_use] -mod macros; -pub mod decoders; -pub mod encoders; -pub mod errors; -pub mod interpreter; -#[cfg(feature = "serde")] -mod serde; -pub mod values; -pub mod vec1; diff --git a/lib/interface-types/src/macros.rs b/lib/interface-types/src/macros.rs deleted file mode 100644 index 88e76748b..000000000 --- a/lib/interface-types/src/macros.rs +++ /dev/null @@ -1,168 +0,0 @@ -//! Collection of helpful macros. - -/// This macro creates a `Vec1` by checking at compile-time that its -/// invariant holds. -#[macro_export] -macro_rules! vec1 { - ($item:expr; 0) => { - compile_error!("Cannot create an empty `Vec1`, it violates its invariant.") - }; - - () => { - compile_error!("Cannot create an empty `Vec1`, it violates its invariant.") - }; - - ($item:expr; $length:expr) => { - { - crate::vec1::Vec1::new(vec![$item; $length]).unwrap() - } - }; - - ($($item:expr),+ $(,)?) => { - { - crate::vec1::Vec1::new(vec![$($item),*]).unwrap() - } - }; -} - -/// This macro runs a parser, extracts the next input and the parser -/// output, and positions the next input on `$input`. -macro_rules! consume { - (($input:ident, $parser_output:ident) = $parser_expression:expr) => { - let (next_input, $parser_output) = $parser_expression; - $input = next_input; - }; - - (($input:ident, mut $parser_output:ident) = $parser_expression:expr) => { - let (next_input, mut $parser_output) = $parser_expression; - $input = next_input; - }; -} - -/// This macro creates an executable instruction for the interpreter. -/// -/// # Example -/// -/// The following example creates a `foo` executable instruction, -/// which takes 2 arguments (`x` and `y`), and does something -/// mysterious by using the `interpreter::Runtime` API. -/// -/// ```rust,ignore -/// executable_instruction!( -/// foo(x: u64, y: u64, instruction_name: String) -> _ { -/// // ^ output type is purposely blank -/// // ^^^^^^^^^^^^^^^^ the instruction name, for debugging purposes -/// // ^ the `y` argument -/// // ^ the `x` argument -/// -/// // an executable instruction is a closure that takes a `Runtime` instance -/// move |runtime| -> _ { -/// // Do something. -/// -/// Ok(()) -/// } -/// ); -/// ``` -/// -/// Check the existing executable instruction to get more examples. -macro_rules! executable_instruction { - ($name:ident ( $($argument_name:ident: $argument_type:ty),* ) -> _ $implementation:block ) => { - pub(crate) fn $name( - $($argument_name: $argument_type),* - ) -> crate::interpreter::ExecutableInstruction - where - Export: crate::interpreter::wasm::structures::Export, - LocalImport: crate::interpreter::wasm::structures::LocalImport, - Memory: crate::interpreter::wasm::structures::Memory, - MemoryView: crate::interpreter::wasm::structures::MemoryView, - Instance: crate::interpreter::wasm::structures::Instance, - { - #[allow(unused_imports)] - use crate::interpreter::{stack::Stackable}; - - Box::new($implementation) - } - }; -} - -#[cfg(test)] -macro_rules! test_executable_instruction { - ( - $test_name:ident = - instructions: [ $($instructions:expr),* $(,)* ], - invocation_inputs: [ $($invocation_inputs:expr),* $(,)* ], - instance: $instance:expr, - stack: [ $($stack:expr),* $(,)* ] - $(,)* - ) => { - #[test] - #[allow(non_snake_case, unused)] - fn $test_name() { - use crate::{ - interpreter::{ - instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView}, - stack::Stackable, - Instruction, Interpreter, - }, - types::InterfaceType, - values::InterfaceValue, - }; - use std::{cell::Cell, collections::HashMap, convert::TryInto}; - - let interpreter: Interpreter = - (&vec![$($instructions),*]).try_into().unwrap(); - - let invocation_inputs = vec![$($invocation_inputs),*]; - let mut instance = $instance; - let run = interpreter.run(&invocation_inputs, &mut instance); - - let err = match &run { - Ok(_) => "".to_string(), - Err(e) => e.to_string(), - }; - - assert!(run.is_ok(), err); - - let stack = run.unwrap(); - - assert_eq!(stack.as_slice(), &[$($stack),*]); - } - }; - - ( - $test_name:ident = - instructions: [ $($instructions:expr),* $(,)* ], - invocation_inputs: [ $($invocation_inputs:expr),* $(,)* ], - instance: $instance:expr, - error: $error:expr - $(,)* - ) => { - #[test] - #[allow(non_snake_case, unused)] - fn $test_name() { - use crate::{ - interpreter::{ - instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView}, - stack::Stackable, - Instruction, Interpreter, - }, - types::InterfaceType, - values::InterfaceValue, - }; - use std::{cell::Cell, collections::HashMap, convert::TryInto}; - - let interpreter: Interpreter = - (&vec![$($instructions),*]).try_into().unwrap(); - - let invocation_inputs = vec![$($invocation_inputs),*]; - let mut instance = $instance; - let run = interpreter.run(&invocation_inputs, &mut instance); - - assert!(run.is_err()); - - let error = run.unwrap_err().to_string(); - - assert_eq!(error, String::from($error)); - } - }; -} diff --git a/lib/interface-types/src/serde/de.rs b/lib/interface-types/src/serde/de.rs deleted file mode 100644 index af8bf44ad..000000000 --- a/lib/interface-types/src/serde/de.rs +++ /dev/null @@ -1,590 +0,0 @@ -//! Provides a deserializer from WIT values to Rust value. - -use crate::{ - types::InterfaceType, - values::{FlattenInterfaceValueIterator, InterfaceValue}, -}; -use serde::{de, Deserialize}; -use std::{ - fmt::{self, Display}, - iter::Peekable, -}; - -/// Deserialize a set of `InterfaceValue`s to a type `T` that -/// implements the `Deserialize` trait. -/// -/// This is not a requirement to use WIT, but Serde provides an even -/// nicer API to the user to rebuild its complex types from WIT -/// values. -/// -/// # Example -/// -/// ```rust -/// use wasmer_interface_types::{ -/// values::{InterfaceValue, from_interface_values}, -/// vec1::Vec1, -/// }; -/// use serde::Deserialize; -/// -/// #[derive(Deserialize, Debug, PartialEq)] -/// struct S(i32, i64); -/// -/// #[derive(Deserialize, Debug, PartialEq)] -/// struct T<'a> { -/// x: &'a str, -/// s: S, -/// y: f32, -/// }; -/// -/// let values = vec![InterfaceValue::Record(Vec1::new(vec![ -/// InterfaceValue::String("abc".to_string()), -/// InterfaceValue::Record(Vec1::new(vec![InterfaceValue::I32(1), InterfaceValue::I64(2)]).unwrap()), -/// InterfaceValue::F32(3.), -/// ]).unwrap())]; -/// let t = from_interface_values::(&values).unwrap(); -/// -/// assert_eq!( -/// t, -/// T { -/// x: "abc", -/// s: S(1, 2), -/// y: 3., -/// } -/// ); -/// ``` -pub fn from_interface_values<'a, T>(values: &'a [InterfaceValue]) -> Result -where - T: Deserialize<'a>, -{ - let mut deserializer = Deserializer::new(values); - let result = T::deserialize(&mut deserializer)?; - - match deserializer.iterator.peek() { - None => Ok(result), - _ => Err(DeserializeError::InputNotEmpty), - } -} - -/// The deserializer. The iterator iterates over `InterfaceValue`s, -/// all flatten, see `FlattenInterfaceValueIterator`. -struct Deserializer<'de> { - iterator: Peekable>, -} - -impl<'de> Deserializer<'de> { - pub fn new(input: &'de [InterfaceValue]) -> Deserializer<'de> { - Deserializer { - iterator: FlattenInterfaceValueIterator::new(input).peekable(), - } - } -} - -macro_rules! next { - ($method_name:ident, $variant:ident, $type:ty) => { - fn $method_name(&mut self) -> Result<$type, DeserializeError> { - match self.iterator.peek() { - Some(InterfaceValue::$variant(value)) => { - self.iterator.next(); - - Ok(*value) - } - - Some(wrong_value) => Err(DeserializeError::TypeMismatch { - expected_type: InterfaceType::$variant, - received_type: (*wrong_value).into(), - }), - - None => Err(DeserializeError::InputEmpty), - } - } - } -} - -impl<'de> Deserializer<'de> { - next!(next_s8, S8, i8); - next!(next_s16, S16, i16); - next!(next_s32, S32, i32); - next!(next_s64, S64, i64); - next!(next_u8, U8, u8); - next!(next_u16, U16, u16); - next!(next_u32, U32, u32); - next!(next_u64, U64, u64); - next!(next_f32, F32, f32); - next!(next_f64, F64, f64); - - fn next_string(&mut self) -> Result<&'de str, DeserializeError> { - match self.iterator.peek() { - Some(InterfaceValue::String(v)) => { - self.iterator.next(); - - Ok(v) - } - - Some(wrong_value) => Err(DeserializeError::TypeMismatch { - expected_type: InterfaceType::String, - received_type: (*wrong_value).into(), - }), - - None => Err(DeserializeError::InputEmpty), - } - } - - next!(next_i32, I32, i32); - next!(next_i64, I64, i64); -} - -/// Represents an error while deserializing. -#[derive(Clone, Debug, PartialEq)] -pub enum DeserializeError { - /// The input isn't empty, i.e. some values aren't deserialized. - InputNotEmpty, - - /// The input is too short! - InputEmpty, - - /// The current value hasn't the expected type. - TypeMismatch { - /// The expected type. - expected_type: InterfaceType, - - /// The received type. - received_type: InterfaceType, - }, - - /// Arbitrary message. - Message(String), -} - -impl de::Error for DeserializeError { - fn custom(msg: T) -> Self { - Self::Message(msg.to_string()) - } -} - -impl Display for DeserializeError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::InputNotEmpty => write!(formatter, "Unexpected input remaining"), - Self::Message(ref msg) => write!(formatter, "{}", msg), - Self::InputEmpty => write!(formatter, "Unexpected end of input"), - Self::TypeMismatch { - ref expected_type, - ref received_type, - } => write!( - formatter, - "Type mismatch detected, expected `{:?}` but received `{:?}`", - expected_type, received_type - ), - } - } -} - -impl std::error::Error for DeserializeError {} - -impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { - type Error = DeserializeError; - - fn deserialize_any(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - match self.iterator.peek() { - Some(InterfaceValue::S8(_)) => self.deserialize_i8(visitor), - Some(InterfaceValue::S16(_)) => self.deserialize_i16(visitor), - Some(InterfaceValue::S32(_)) => self.deserialize_i32(visitor), - Some(InterfaceValue::S64(_)) => self.deserialize_i64(visitor), - Some(InterfaceValue::U8(_)) => self.deserialize_u8(visitor), - Some(InterfaceValue::U16(_)) => self.deserialize_u16(visitor), - Some(InterfaceValue::U32(_)) => self.deserialize_u32(visitor), - Some(InterfaceValue::U64(_)) => self.deserialize_u64(visitor), - Some(InterfaceValue::F32(_)) => self.deserialize_f32(visitor), - Some(InterfaceValue::F64(_)) => self.deserialize_f64(visitor), - Some(InterfaceValue::String(_)) => self.deserialize_string(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 - None => Err(DeserializeError::InputEmpty), - } - } - - fn deserialize_bool(self, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - unimplemented!("`bool` is not supported by WIT for the moment.") - } - - fn deserialize_i8(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_i8(self.next_s8()?) - } - - fn deserialize_i16(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_i16(self.next_s16()?) - } - - fn deserialize_i32(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - // Both `InterfaceValue::S32` and `InterfaceValue::I32` - // represent `i32`. - visitor.visit_i32(self.next_s32().or_else(|_| self.next_i32())?) - } - - fn deserialize_i64(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - // Both `InterfaceValue::S64` and `InterfaceValue::I64` - // represent `i64`. - visitor.visit_i64(self.next_s64().or_else(|_| self.next_i64())?) - } - - fn deserialize_u8(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_u8(self.next_u8()?) - } - - fn deserialize_u16(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_u16(self.next_u16()?) - } - - fn deserialize_u32(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_u32(self.next_u32()?) - } - - fn deserialize_u64(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_u64(self.next_u64()?) - } - - fn deserialize_f32(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_f32(self.next_f32()?) - } - - fn deserialize_f64(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_f64(self.next_f64()?) - } - - fn deserialize_char(self, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!("`char` is not supported by WIT for the moment.") - } - - fn deserialize_str(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_borrowed_str(self.next_string()?) - } - - fn deserialize_string(self, visitor: V) -> Result - where - V: de::Visitor<'de>, - { - self.deserialize_str(visitor) - } - - fn deserialize_bytes(self, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!("`bytes` is not supported by WIT for the moment.") - } - - fn deserialize_byte_buf(self, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!("`bytes` buffer is not supported by WIT for the moment.") - } - - fn deserialize_option(self, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!("`option` is not supported by WIT for the moment.") - } - - fn deserialize_unit(self, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!("`unit` is not supported by WIT for the moment.") - } - - fn deserialize_unit_struct( - self, - _name: &'static str, - _visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - todo!("`unit_struct` is not supported by WIT for the moment.") - } - - fn deserialize_newtype_struct( - self, - _name: &'static str, - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_newtype_struct(self) - } - - fn deserialize_seq(self, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!("`seq` is not supported by WIT for the moment.") - } - - fn deserialize_tuple(self, _len: usize, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!("`tuple` is not supported by WIT for the moment.") - } - - fn deserialize_tuple_struct( - mut self, - _name: &'static str, - _len: usize, - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_seq(Sequence::new(&mut self)) - } - - fn deserialize_map(self, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!("`map` is not supported by WIT for the moment.") - } - - fn deserialize_struct( - mut self, - _name: &'static str, - _fields: &'static [&'static str], - visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - visitor.visit_seq(Sequence::new(&mut self)) - } - - fn deserialize_enum( - self, - _name: &'static str, - _variants: &'static [&'static str], - _visitor: V, - ) -> Result - where - V: de::Visitor<'de>, - { - todo!("`enum` is not supported by WIT for the moment.") - } - - fn deserialize_identifier(self, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!("`identifier` is not supported by WIT for the moment."); - } - - fn deserialize_ignored_any(self, _visitor: V) -> Result - where - V: de::Visitor<'de>, - { - todo!("`ignored_any` is not implemented for the moment.") - } -} - -struct Sequence<'a, 'de> -where - 'de: 'a, -{ - de: &'a mut Deserializer<'de>, -} - -impl<'a, 'de> Sequence<'a, 'de> { - fn new(de: &'a mut Deserializer<'de>) -> Self { - Sequence { de } - } -} - -impl<'de, 'a> de::SeqAccess<'de> for Sequence<'a, 'de> { - type Error = DeserializeError; - - fn next_element_seed(&mut self, seed: T) -> Result, Self::Error> - where - T: de::DeserializeSeed<'de>, - { - if self.de.iterator.peek().is_none() { - return Ok(None); - } - - seed.deserialize(&mut *self.de).map(Some) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! deserialize_value { - ($test_name:ident, $variant:ident, $ty:ident, $value:expr) => { - #[test] - #[allow(non_snake_case)] - fn $test_name() { - let input = vec![InterfaceValue::$variant($value)]; - let output: $ty = $value; - - assert_eq!(from_interface_values::<$ty>(&input).unwrap(), output); - } - }; - } - - deserialize_value!(test_deserialize_value__s8, S8, i8, 42); - deserialize_value!(test_deserialize_value__s16, S16, i16, 42); - deserialize_value!(test_deserialize_value__s32, S32, i32, 42); - deserialize_value!(test_deserialize_value__s64, S64, i64, 42); - deserialize_value!(test_deserialize_value__u8, U8, u8, 42); - deserialize_value!(test_deserialize_value__u16, U16, u16, 42); - deserialize_value!(test_deserialize_value__u32, U32, u32, 42); - deserialize_value!(test_deserialize_value__u64, U64, u64, 42); - deserialize_value!(test_deserialize_value__f32, F32, f32, 42.); - deserialize_value!(test_deserialize_value__f64, F32, f32, 42.); - deserialize_value!( - test_deserialize_value__string, - String, - String, - "foo".to_string() - ); - - #[test] - #[allow(non_snake_case)] - fn test_deserialize_value__str() { - let foo = "foo".to_string(); - let values = vec![InterfaceValue::String(foo)]; - let input: &str = from_interface_values(&values).unwrap(); - let output: &str = "foo"; - - assert_eq!(input, output); - } - - deserialize_value!(test_deserialize_value__i32, I32, i32, 42); - deserialize_value!(test_deserialize_value__i64, I64, i64, 42); - - #[test] - #[allow(non_snake_case)] - fn test_deserialize_value__newtype_struct() { - #[derive(Deserialize, Debug, PartialEq)] - struct S(i8); - - let input = vec![InterfaceValue::Record(vec1![InterfaceValue::S8(42)])]; - let output = S(42); - - assert_eq!(from_interface_values::(&input).unwrap(), output); - } - - #[test] - #[allow(non_snake_case)] - fn test_deserialize_value__tuple_struct() { - #[derive(Deserialize, Debug, PartialEq)] - struct S(i8, f32); - - let input = vec![InterfaceValue::Record(vec1![ - InterfaceValue::S8(7), - InterfaceValue::F32(42.), - ])]; - let output = S(7, 42.); - - assert_eq!(from_interface_values::(&input).unwrap(), output); - } - - #[test] - #[allow(non_snake_case)] - fn test_deserialize_value__struct() { - #[derive(Deserialize, Debug, PartialEq)] - struct S { - x: i8, - y: f32, - } - - let input = vec![InterfaceValue::Record(vec1![ - InterfaceValue::S8(7), - InterfaceValue::F32(42.), - ])]; - let output = S { x: 7, y: 42. }; - - assert_eq!(from_interface_values::(&input).unwrap(), output); - } - - #[test] - #[allow(non_snake_case)] - fn test_deserialize_value__struct_nested() { - #[derive(Deserialize, Debug, PartialEq)] - struct Point { - x: i32, - y: i32, - z: i32, - } - - #[derive(Deserialize, Debug, PartialEq)] - struct Line { - p1: Point, - p2: Point, - } - - let input = vec![InterfaceValue::Record(vec1![ - InterfaceValue::Record(vec1![ - InterfaceValue::I32(1), - InterfaceValue::I32(2), - InterfaceValue::I32(3), - ]), - InterfaceValue::Record(vec1![ - InterfaceValue::I32(4), - InterfaceValue::I32(5), - InterfaceValue::I32(6), - ]), - ])]; - let output = Line { - p1: Point { x: 1, y: 2, z: 3 }, - p2: Point { x: 4, y: 5, z: 6 }, - }; - - assert_eq!(from_interface_values::(&input).unwrap(), output); - } -} diff --git a/lib/interface-types/src/serde/mod.rs b/lib/interface-types/src/serde/mod.rs deleted file mode 100644 index 6cc35e278..000000000 --- a/lib/interface-types/src/serde/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Serde is not necessary to use WIT. It only provides a nicer API -//! for the end-user to send or receive its complex types to/from WIT -//! values, like `record` for instance. - -pub(crate) mod de; -pub(crate) mod ser; diff --git a/lib/interface-types/src/serde/ser.rs b/lib/interface-types/src/serde/ser.rs deleted file mode 100644 index 093a5d514..000000000 --- a/lib/interface-types/src/serde/ser.rs +++ /dev/null @@ -1,581 +0,0 @@ -//! Provides a serializer from Rust value to WIT values. - -use crate::{values::InterfaceValue, vec1::Vec1}; -use serde::{ser, Serialize}; -use std::fmt::{self, Display}; - -/// Serialize a type `T` that implements the `Serialize` trait to an -/// `InterfaceValue`. -/// -/// This is not a requirement to use WIT, but Serde provides an even -/// nicer API to the user to send its complex types to WIT. -/// -/// # Example -/// -/// ```rust -/// use wasmer_interface_types::{ -/// values::{InterfaceValue, to_interface_value}, -/// vec1::Vec1, -/// }; -/// use serde::Serialize; -/// -/// #[derive(Serialize)] -/// struct S(i32, i64); -/// -/// #[derive(Serialize)] -/// struct T { -/// x: String, -/// s: S, -/// y: f32, -/// }; -/// -/// let input = T { -/// x: "abc".to_string(), -/// s: S(1, 2), -/// y: 3., -/// }; -/// -/// assert_eq!( -/// to_interface_value(&input).unwrap(), -/// InterfaceValue::Record(Vec1::new(vec![ -/// InterfaceValue::String("abc".to_string()), -/// InterfaceValue::Record(Vec1::new(vec![InterfaceValue::I32(1), InterfaceValue::I64(2)]).unwrap()), -/// InterfaceValue::F32(3.), -/// ]).unwrap()), -/// ); -/// ``` -pub fn to_interface_value(value: &T) -> Result -where - T: Serialize, -{ - let mut serializer = Serializer::new(); - value.serialize(&mut serializer)?; - - if serializer.values.len() != 1 { - Err(SerializeError::TransformationNotFinished) - } else { - let mut first_values = serializer.values.pop().unwrap(); // this `unwrap` is safe because we are sure the length is 1. - - if first_values.len() != 1 { - Err(SerializeError::TransformationNotFinished) - } else { - let first_value = first_values.pop().unwrap(); // this `unwrap` is safe because we are sure the length is 1. - - Ok(first_value) - } - } -} - -/// The serializer. -struct Serializer { - values: Vec>, -} - -impl Serializer { - fn new() -> Self { - Self { - values: vec![vec![]], - } - } - - fn last(&mut self) -> &mut Vec { - self.values.last_mut().unwrap() - } - - fn push_with_capacity(&mut self, capacity: usize) { - self.values.push(Vec::with_capacity(capacity)); - } - - fn pop(&mut self) -> Result, SerializeError> { - // The first `vec` contains the final result. It is forbidden - // to `pop` it as is. - if self.values.len() < 2 { - Err(SerializeError::InternalValuesCorrupted) - } else { - Ok(self.values.pop().unwrap()) // this `unwrap` is safe before `self.values` contains at least 2 items - } - } -} - -/// Represents an error while serializing. -#[derive(Clone, Debug, PartialEq)] -pub enum SerializeError { - /// The serialization still has pending values internally. - TransformationNotFinished, - - /// The internal values have been corrupted during the - /// serialization. - InternalValuesCorrupted, - - /// A record must contain at least one field. - RecordNeedsAtLeastOneField, - - /// Arbitrary message. - Message(String), -} - -impl ser::Error for SerializeError { - fn custom(msg: T) -> Self { - Self::Message(msg.to_string()) - } -} - -impl Display for SerializeError { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::TransformationNotFinished => write!( - formatter, - "serialization still has pending values internally, something incorrect happened" - ), - Self::InternalValuesCorrupted => write!( - formatter, - "the internal values have been corrutped during the serialization" - ), - Self::RecordNeedsAtLeastOneField => write!( - formatter, - "a record must contain at least one field, zero given" - ), - Self::Message(ref msg) => write!(formatter, "{}", msg), - } - } -} - -impl std::error::Error for SerializeError {} - -impl<'a> ser::Serializer for &'a mut Serializer { - type Ok = (); - type Error = SerializeError; - - type SerializeSeq = Self; - type SerializeTuple = Self; - type SerializeTupleStruct = Self; - type SerializeTupleVariant = Self; - type SerializeMap = Self; - type SerializeStruct = Self; - type SerializeStructVariant = Self; - - fn serialize_bool(self, _value: bool) -> Result { - unimplemented!("`bool` is not supported by WIT for the moment.") - } - - fn serialize_i8(self, value: i8) -> Result { - self.last().push(value.into()); - - Ok(()) - } - - fn serialize_i16(self, value: i16) -> Result { - self.last().push(value.into()); - - Ok(()) - } - - fn serialize_i32(self, value: i32) -> Result { - self.last().push(value.into()); - - Ok(()) - } - - fn serialize_i64(self, value: i64) -> Result { - self.last().push(value.into()); - - Ok(()) - } - - fn serialize_u8(self, value: u8) -> Result { - self.last().push(value.into()); - - Ok(()) - } - - fn serialize_u16(self, value: u16) -> Result { - self.last().push(value.into()); - - Ok(()) - } - - fn serialize_u32(self, value: u32) -> Result { - self.last().push(value.into()); - - Ok(()) - } - - fn serialize_u64(self, value: u64) -> Result { - self.last().push(value.into()); - - Ok(()) - } - - fn serialize_f32(self, value: f32) -> Result { - self.last().push(value.into()); - - Ok(()) - } - - fn serialize_f64(self, value: f64) -> Result { - self.last().push(value.into()); - - Ok(()) - } - - fn serialize_char(self, _value: char) -> Result { - todo!("`char` is not supported by WIT for the moment.") - } - - fn serialize_str(self, value: &str) -> Result { - self.last().push(value.to_owned().into()); - - Ok(()) - } - - fn serialize_bytes(self, _value: &[u8]) -> Result { - todo!("`bytes` is not supported by WIT for the moment.") - } - - fn serialize_none(self) -> Result { - self.serialize_unit() - } - - fn serialize_some(self, _value: &T) -> Result - where - T: ?Sized + Serialize, - { - todo!("`some` is not supported by WIT for the moment.") - } - - fn serialize_unit(self) -> Result { - todo!("`unit` is not supported by WIT for the moment.") - } - - fn serialize_unit_struct(self, _name: &'static str) -> Result { - todo!("`unit_struct` is not supported by WIT for the moment.") - } - - fn serialize_unit_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - ) -> Result { - todo!("`unit_variant` is not supported by WIT for the moment.") - } - - fn serialize_newtype_struct( - self, - _name: &'static str, - value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - value.serialize(self) - } - - fn serialize_newtype_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - todo!("`newtype_variant` is not supported by WIT for the moment.") - } - - fn serialize_seq(self, _len: Option) -> Result { - todo!("`seq` is not supported by WIT for the moment.") - } - - fn serialize_tuple(self, _len: usize) -> Result { - todo!("`tuple` is not supported by WIT for the moment.") - } - - fn serialize_tuple_struct( - self, - _name: &'static str, - len: usize, - ) -> Result { - self.push_with_capacity(len); - - Ok(self) - } - - fn serialize_tuple_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - todo!("`tuple_variant` is not supported by WIT for the moment.") - } - - fn serialize_map(self, _len: Option) -> Result { - todo!("`map` is not supported by WIT for the moment.") - } - - fn serialize_struct( - self, - _name: &'static str, - len: usize, - ) -> Result { - self.push_with_capacity(len); - - Ok(self) - } - - fn serialize_struct_variant( - self, - _name: &'static str, - _variant_index: u32, - _variant: &'static str, - _len: usize, - ) -> Result { - todo!("`struct_variant` is not supported by WIT for the moment.") - } -} - -impl<'a> ser::SerializeSeq for &'a mut Serializer { - type Ok = (); - type Error = SerializeError; - - fn serialize_element(&mut self, _value: &T) -> Result - where - T: ?Sized + Serialize, - { - unimplemented!() - } - - fn end(self) -> Result { - unimplemented!() - } -} - -impl<'a> ser::SerializeTuple for &'a mut Serializer { - type Ok = (); - type Error = SerializeError; - - fn serialize_element(&mut self, _value: &T) -> Result - where - T: ?Sized + Serialize, - { - unimplemented!() - } - - fn end(self) -> Result { - unimplemented!() - } -} - -impl<'a> ser::SerializeTupleStruct for &'a mut Serializer { - type Ok = (); - type Error = SerializeError; - - fn serialize_field(&mut self, value: &T) -> Result - where - T: ?Sized + Serialize, - { - value.serialize(&mut **self) - } - - fn end(self) -> Result { - let record = InterfaceValue::Record( - Vec1::new(self.pop()?).map_err(|_| Self::Error::RecordNeedsAtLeastOneField)?, - ); - self.last().push(record); - - Ok(()) - } -} - -impl<'a> ser::SerializeTupleVariant for &'a mut Serializer { - type Ok = (); - type Error = SerializeError; - - fn serialize_field(&mut self, _value: &T) -> Result - where - T: ?Sized + Serialize, - { - unimplemented!() - } - - fn end(self) -> Result { - unimplemented!() - } -} - -impl<'a> ser::SerializeMap for &'a mut Serializer { - type Ok = (); - type Error = SerializeError; - - fn serialize_key(&mut self, _key: &T) -> Result - where - T: ?Sized + Serialize, - { - unimplemented!() - } - - fn serialize_value(&mut self, _value: &T) -> Result - where - T: ?Sized + Serialize, - { - unimplemented!() - } - - fn end(self) -> Result { - unimplemented!() - } -} - -impl<'a> ser::SerializeStruct for &'a mut Serializer { - type Ok = (); - type Error = SerializeError; - - fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result - where - T: ?Sized + Serialize, - { - value.serialize(&mut **self) - } - - fn end(self) -> Result { - let record = InterfaceValue::Record( - Vec1::new(self.pop()?).map_err(|_| Self::Error::RecordNeedsAtLeastOneField)?, - ); - self.last().push(record); - - Ok(()) - } -} - -impl<'a> ser::SerializeStructVariant for &'a mut Serializer { - type Ok = (); - type Error = SerializeError; - - fn serialize_field( - &mut self, - _key: &'static str, - _value: &T, - ) -> Result - where - T: ?Sized + Serialize, - { - unimplemented!() - } - - fn end(self) -> Result { - unimplemented!() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! serialize_value { - ($test_name:ident, $ty:ident, $variant:ident, $value:expr) => { - #[test] - #[allow(non_snake_case)] - fn $test_name() { - let input: $ty = $value; - let output = InterfaceValue::$variant($value); - - assert_eq!(to_interface_value(&input).unwrap(), output); - } - }; - } - - serialize_value!(test_serialize_value__s8, i8, S8, 42); - serialize_value!(test_serialize_value__s16, i16, S16, 42); - serialize_value!(test_serialize_value__i32, i32, I32, 42); - serialize_value!(test_serialize_value__i64, i64, I64, 42); - serialize_value!(test_serialize_value__u8, u8, U8, 42); - serialize_value!(test_serialize_value__u16, u16, U16, 42); - serialize_value!(test_serialize_value__u32, u32, U32, 42); - serialize_value!(test_serialize_value__u64, u64, U64, 42); - serialize_value!(test_serialize_value__f32, f32, F32, 42.); - serialize_value!(test_serialize_value__f64, f32, F32, 42.); - serialize_value!( - test_serialize_value__string, - String, - String, - "foo".to_string() - ); - - #[test] - #[allow(non_snake_case)] - fn test_serialize_value__newtype_struct() { - #[derive(Serialize)] - struct S(i8); - - let input = S(42); - let output = InterfaceValue::S8(42); - - assert_eq!(to_interface_value(&input).unwrap(), output); - } - - #[test] - #[allow(non_snake_case)] - fn test_serialize_value__tuple_struct() { - #[derive(Serialize)] - struct S(i8, f32); - - let input = S(7, 42.); - let output = InterfaceValue::Record(vec1![InterfaceValue::S8(7), InterfaceValue::F32(42.)]); - - assert_eq!(to_interface_value(&input).unwrap(), output); - } - - #[test] - #[allow(non_snake_case)] - fn test_serialize_value__struct() { - #[derive(Serialize)] - struct S { - x: i8, - y: f32, - } - - let input = S { x: 7, y: 42. }; - let output = InterfaceValue::Record(vec1![InterfaceValue::S8(7), InterfaceValue::F32(42.)]); - - assert_eq!(to_interface_value(&input).unwrap(), output); - } - - #[test] - #[allow(non_snake_case)] - fn test_serialize_value__struct_nested() { - #[derive(Serialize)] - struct Point { - x: i32, - y: i32, - z: i32, - } - - #[derive(Serialize)] - struct Line { - p1: Point, - p2: Point, - } - - let input = Line { - p1: Point { x: 1, y: 2, z: 3 }, - p2: Point { x: 4, y: 5, z: 6 }, - }; - let output = InterfaceValue::Record(vec1![ - InterfaceValue::Record(vec1![ - InterfaceValue::I32(1), - InterfaceValue::I32(2), - InterfaceValue::I32(3), - ]), - InterfaceValue::Record(vec1![ - InterfaceValue::I32(4), - InterfaceValue::I32(5), - InterfaceValue::I32(6), - ]), - ]); - - assert_eq!(to_interface_value(&input).unwrap(), output); - } -} diff --git a/lib/interface-types/src/types.rs b/lib/interface-types/src/types.rs deleted file mode 100644 index 48ac786c5..000000000 --- a/lib/interface-types/src/types.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! This module defines the WIT types. - -use crate::vec1::Vec1; - -/// Represents the types supported by WIT. -#[derive(PartialEq, Debug, Clone)] -pub enum InterfaceType { - /// A 8-bits signed integer. - S8, - - /// A 16-bits signed integer. - S16, - - /// A 32-bits signed integer. - S32, - - /// A 64-bits signed integer. - S64, - - /// A 8-bits unsigned integer. - U8, - - /// A 16-bits unsigned integer. - U16, - - /// A 32-bits unsigned integer. - U32, - - /// A 64-bits unsigned integer. - U64, - - /// A 32-bits float. - F32, - - /// A 64-bits float. - F64, - - /// A string. - String, - - /// An `any` reference. - Anyref, - - /// A 32-bits integer (as defined in WebAssembly core). - I32, - - /// A 64-bits integer (as defiend in WebAssembly core). - I64, - - /// A record. - Record(RecordType), -} - -/// Represents a record type. -#[derive(PartialEq, Debug, Clone)] -pub struct RecordType { - /// Types representing the fields. - /// A record must have at least one field, hence the - /// [`Vec1`][crate::vec1::Vec1]. - pub fields: Vec1, -} diff --git a/lib/interface-types/src/values.rs b/lib/interface-types/src/values.rs deleted file mode 100644 index 2bb871e16..000000000 --- a/lib/interface-types/src/values.rs +++ /dev/null @@ -1,250 +0,0 @@ -//! Defines WIT values and associated operations. - -use crate::{ - errors::WasmValueNativeCastError, - types::{InterfaceType, RecordType}, - vec1::Vec1, -}; -use std::{convert::TryFrom, slice::Iter}; - -#[cfg(feature = "serde")] -pub use crate::serde::{de::from_interface_values, ser::to_interface_value}; - -/// A WIT value. -#[derive(Debug, Clone, PartialEq)] -pub enum InterfaceValue { - /// A 8-bits signed integer. - S8(i8), - - /// A 16-bits signed integer. - S16(i16), - - /// A 32-bits signed integer. - S32(i32), - - /// A 64-bits signed integer. - S64(i64), - - /// A 8-bits unsigned integer. - U8(u8), - - /// A 16-bits unsigned integer. - U16(u16), - - /// A 32-bits unsigned integer. - U32(u32), - - /// A 64-bits unsigned integer. - U64(u64), - - /// A 32-bits float. - F32(f32), - - /// A 64-bits float. - F64(f64), - - /// A string. - String(String), - - //Anyref(?), - /// A 32-bits integer (as defined in WebAssembly core). - I32(i32), - - /// A 64-bits integer (as defiend in WebAssembly core). - I64(i64), - - /// A record. - Record(Vec1), -} - -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::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> for RecordType { - fn from(values: &Vec) -> 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. - const INTERFACE_TYPE: InterfaceType; -} - -macro_rules! native { - ($native_type:ty, $variant:ident) => { - impl NativeType for $native_type { - const INTERFACE_TYPE: InterfaceType = InterfaceType::$variant; - } - - impl From<$native_type> for InterfaceValue { - fn from(n: $native_type) -> Self { - Self::$variant(n) - } - } - - impl TryFrom<&InterfaceValue> for $native_type { - type Error = WasmValueNativeCastError; - - fn try_from(w: &InterfaceValue) -> Result { - match w { - InterfaceValue::$variant(n) => Ok(n.clone()), - _ => Err(WasmValueNativeCastError { - from: w.into(), - to: <$native_type>::INTERFACE_TYPE, - }), - } - } - } - }; -} - -native!(i8, S8); -native!(i16, S16); -native!(i32, I32); -native!(i64, I64); -native!(u8, U8); -native!(u16, U16); -native!(u32, U32); -native!(u64, U64); -native!(f32, F32); -native!(f64, F64); -native!(String, String); - -/// Iterates over a vector of `InterfaceValues` but flatten all the -/// values. So `I32(1), Record([I32(2), I32(3)]), I32(4)` will be -/// iterated like `I32(1), I32(2), I32(3), I32(4)`. -pub(crate) struct FlattenInterfaceValueIterator<'a> { - iterators: Vec>, -} - -impl<'a> FlattenInterfaceValueIterator<'a> { - pub(crate) fn new(values: &'a [InterfaceValue]) -> Self { - Self { - iterators: vec![values.iter()], - } - } -} - -impl<'a> Iterator for FlattenInterfaceValueIterator<'a> { - type Item = &'a InterfaceValue; - - fn next(&mut self) -> Option { - match self.iterators.last_mut()?.next() { - // End of the current iterator, go back to the previous - // one. - None => { - self.iterators.pop(); - self.next() - } - - // Recursively iterate over the record. - Some(InterfaceValue::Record(values)) => { - self.iterators.push(values.iter()); - self.next() - } - - // A regular item. - e @ Some(_) => e, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! value_to_type { - ($test_name:ident, $ty:ident, $value:expr) => { - #[test] - #[allow(non_snake_case)] - fn $test_name() { - assert_eq!( - InterfaceType::from(&InterfaceValue::$ty($value)), - InterfaceType::$ty - ); - } - }; - } - - value_to_type!(interface_type_from_interface_value__s8, S8, 42); - value_to_type!(interface_type_from_interface_value__s16, S16, 42); - value_to_type!(interface_type_from_interface_value__s32, S32, 42); - value_to_type!(interface_type_from_interface_value__s64, S64, 42); - value_to_type!(interface_type_from_interface_value__u8, U8, 42); - value_to_type!(interface_type_from_interface_value__u16, U16, 42); - value_to_type!(interface_type_from_interface_value__u32, U32, 42); - value_to_type!(interface_type_from_interface_value__u64, U64, 42); - value_to_type!(interface_type_from_interface_value__f32, F32, 42.); - value_to_type!(interface_type_from_interface_value__f64, F64, 42.); - value_to_type!( - interface_type_from_interface_value__string, - String, - "foo".to_string() - ); - value_to_type!(interface_type_from_interface_value__i32, I32, 42); - value_to_type!(interface_type_from_interface_value__i64, I64, 42); - - #[test] - #[allow(non_snake_case)] - fn interface_type_from_interface_value__record() { - assert_eq!( - InterfaceType::from(&InterfaceValue::Record(vec1![ - InterfaceValue::I32(1), - InterfaceValue::S8(2) - ])), - InterfaceType::Record(RecordType { - fields: vec1![InterfaceType::I32, InterfaceType::S8] - }) - ); - - assert_eq!( - InterfaceType::from(&InterfaceValue::Record(vec1![ - InterfaceValue::I32(1), - InterfaceValue::Record(vec1![ - InterfaceValue::String("a".to_string()), - InterfaceValue::F64(42.) - ]), - InterfaceValue::S8(2) - ])), - InterfaceType::Record(RecordType { - fields: vec1![ - InterfaceType::I32, - InterfaceType::Record(RecordType { - fields: vec1![InterfaceType::String, InterfaceType::F64] - }), - InterfaceType::S8 - ] - }) - ); - } -} diff --git a/lib/interface-types/src/vec1.rs b/lib/interface-types/src/vec1.rs deleted file mode 100644 index 3e89293a6..000000000 --- a/lib/interface-types/src/vec1.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! `Vec1` represents a non-empty `Vec`. - -use std::{ - error, - fmt::{self, Debug}, - ops, -}; - -/// `Vec1` represents a non-empty `Vec`. It derefs to `Vec` -/// directly. -#[derive(Clone, PartialEq)] -pub struct Vec1(Vec) -where - T: Debug; - -/// Represents the only error that can be emitted by `Vec1`, i.e. when -/// the number of items is zero. -#[derive(Debug)] -pub struct EmptyVec; - -impl error::Error for EmptyVec {} - -impl fmt::Display for EmptyVec { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "Vec1 must as least contain one item, zero given") - } -} - -impl Vec1 -where - T: Debug, -{ - /// Creates a new non-empty vector, based on an inner `Vec`. If - /// the inner vector is empty, a `EmptyVec` error is returned. - pub fn new(items: Vec) -> Result { - if items.len() == 0 { - Err(EmptyVec) - } else { - Ok(Self(items)) - } - } -} - -impl fmt::Debug for Vec1 -where - T: Debug, -{ - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(formatter, "{:?}", self.0) - } -} - -impl ops::Deref for Vec1 -where - T: Debug, -{ - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} diff --git a/lib/interface-types/tests/binary.rs b/lib/interface-types/tests/binary.rs deleted file mode 100644 index 81f87304f..000000000 --- a/lib/interface-types/tests/binary.rs +++ /dev/null @@ -1,53 +0,0 @@ -use wasmer_interface_types::{ - ast::*, decoders::binary::parse, encoders::binary::ToBytes, interpreter::Instruction, types::*, - vec1, -}; - -/// Tests an AST to binary, then binary to AST roundtrip. -#[test] -fn test_binary_encoding_decoding_roundtrip() { - let original_ast = Interfaces { - types: vec![ - Type::Function { - inputs: vec![], - outputs: vec![], - }, - Type::Function { - inputs: vec![InterfaceType::I32, InterfaceType::I32], - outputs: vec![InterfaceType::S32], - }, - Type::Record(RecordType { - fields: vec1![InterfaceType::String, InterfaceType::I32], - }), - ], - imports: vec![Import { - namespace: "a", - name: "b", - signature_type: 0, - }], - 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![]; - - original_ast - .to_bytes(&mut binary) - .expect("Failed to encode the AST."); - - let (remainder, ast) = parse::<()>(binary.as_slice()).expect("Failed to decode the AST."); - - assert!(remainder.is_empty()); - - assert_eq!(original_ast, ast); -}