wasmer-interface-types 0.17.0

WebAssembly Interface Types library for Wasmer
Documentation
//! 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<u8> for TypeKind {
    type Error = &'static str;

    fn try_from(code: u8) -> Result<Self, Self::Error> {
        Ok(match code {
            0x00 => Self::Function,
            0x01 => Self::Record,
            _ => return Err("Unknown type kind code."),
        })
    }
}

/// Parse an interface kind.
impl TryFrom<u8> for InterfaceKind {
    type Error = &'static str;

    fn try_from(code: u8) -> Result<Self, Self::Error> {
        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<I>, 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<Type>, 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<Import>, 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<Adapter>, 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<Export>, 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<Implementation>, 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);
    }
}