nowasm 0.0.2

No-std, no-unsafe and no-dependencies WebAssembly 1.0 runtime library
Documentation
use crate::{
    components::{
        Code, Data, Elem, Export, Func, Funcidx, Functype, Global, Import, Memtype, Tabletype,
        Typeidx,
    },
    decode::Decode,
    execute::ExecuteError,
    reader::Reader,
    vector::Vector,
    DecodeError, ModuleInstance, Resolve, VectorFactory,
};
use core::fmt::{Debug, Formatter};

const SECTION_ID_CUSTOM: u8 = 0;
const SECTION_ID_TYPE: u8 = 1;
const SECTION_ID_IMPORT: u8 = 2;
const SECTION_ID_FUNCTION: u8 = 3;
const SECTION_ID_TABLE: u8 = 4;
const SECTION_ID_MEMORY: u8 = 5;
const SECTION_ID_GLOBAL: u8 = 6;
const SECTION_ID_EXPORT: u8 = 7;
const SECTION_ID_START: u8 = 8;
const SECTION_ID_ELEMENT: u8 = 9;
const SECTION_ID_CODE: u8 = 10;
const SECTION_ID_DATA: u8 = 11;

pub struct Module<V: VectorFactory> {
    types: V::Vector<Functype<V>>,
    funcs: V::Vector<Func<V>>,
    table: Option<Tabletype>,
    imports: V::Vector<Import<V>>,
    mem: Option<Memtype>,
    globals: V::Vector<Global>,
    elems: V::Vector<Elem<V>>,
    datas: V::Vector<Data<V>>,
    start: Option<Funcidx>,
    exports: V::Vector<Export<V>>,
}

impl<V: VectorFactory> Module<V> {
    pub fn decode(wasm_bytes: &[u8]) -> Result<Self, DecodeError> {
        let mut this = Self {
            types: V::create_vector(None),
            funcs: V::create_vector(None),
            table: None,
            mem: None,
            globals: V::create_vector(None),
            elems: V::create_vector(None),
            datas: V::create_vector(None),
            start: None,
            imports: V::create_vector(None),
            exports: V::create_vector(None),
        };
        let mut reader = Reader::new(wasm_bytes);

        // Preamble
        let _ = Magic::decode(&mut reader)?;
        let _ = Version::decode(&mut reader)?;

        // Sections
        this.decode_sections(&mut reader)?;

        Ok(this)
    }

    fn decode_sections(&mut self, reader: &mut Reader) -> Result<(), DecodeError> {
        let mut last_section_id = SECTION_ID_CUSTOM;
        let mut function_section: V::Vector<Typeidx> = V::create_vector(None);
        while !reader.is_empty() {
            let section_id = reader.read_u8()?;
            let section_size = reader.read_u32()? as usize;
            let mut section_reader = Reader::new(reader.read(section_size)?);

            if section_id == SECTION_ID_CUSTOM {
                continue;
            }

            if section_id < last_section_id {
                return Err(DecodeError::InvalidSectionOrder {
                    current_section_id: section_id,
                    last_section_id,
                });
            }

            match section_id {
                SECTION_ID_TYPE => {
                    self.types = Decode::<V>::decode_vector(&mut section_reader)?;
                }
                SECTION_ID_IMPORT => {
                    self.imports = Decode::<V>::decode_vector(&mut section_reader)?;
                }
                SECTION_ID_FUNCTION => {
                    function_section = Decode::<V>::decode_vector(&mut section_reader)?;
                }
                SECTION_ID_TABLE => {
                    let value = section_reader.read_u32()? as usize;
                    if value > 1 {
                        return Err(DecodeError::InvalidTableCount { value });
                    }
                    if value == 1 {
                        let table = Decode::<V>::decode(&mut section_reader)?;
                        self.table = Some(table);
                    }
                }
                SECTION_ID_MEMORY => {
                    let value = section_reader.read_u32()? as usize;
                    if value > 1 {
                        return Err(DecodeError::InvalidMemoryCount { value });
                    }
                    if value == 1 {
                        let mem = Decode::<V>::decode(&mut section_reader)?;
                        self.mem = Some(mem);
                    }
                }
                SECTION_ID_GLOBAL => {
                    self.globals = Decode::<V>::decode_vector(&mut section_reader)?;
                }
                SECTION_ID_EXPORT => {
                    self.exports = Decode::<V>::decode_vector(&mut section_reader)?;
                }
                SECTION_ID_START => {
                    self.start = Some(Decode::<V>::decode(&mut section_reader)?);
                }
                SECTION_ID_ELEMENT => {
                    self.elems = Decode::<V>::decode_vector(&mut section_reader)?;
                }
                SECTION_ID_CODE => {
                    let code_section: V::Vector<Code<V>> =
                        Decode::<V>::decode_vector(&mut section_reader)?;
                    if function_section.len() != code_section.len() {
                        return Err(DecodeError::MismatchFunctionAndCodeSectionSize {
                            function_section_size: function_section.len(),
                            code_section_size: code_section.len(),
                        });
                    }
                    self.funcs = V::create_vector(Some(function_section.len()));
                    for (&ty, code) in function_section.iter().zip(code_section.iter()) {
                        self.funcs.push(Func {
                            ty,
                            locals: V::clone_vector(&code.locals),
                            body: code.body.clone(),
                        });
                    }
                }
                SECTION_ID_DATA => {
                    self.datas = Decode::<V>::decode_vector(&mut section_reader)?;
                }
                _ => {
                    return Err(DecodeError::InvalidSectionId { value: section_id });
                }
            }
            last_section_id = section_id;

            if !section_reader.is_empty() {
                return Err(DecodeError::InvalidSectionByteSize {
                    section_id,
                    expected_byte_size: section_size,
                    actual_byte_size: section_reader.position(),
                });
            }
        }
        Ok(())
    }

    pub fn instantiate<R>(self, resolver: R) -> Result<ModuleInstance<V, R::HostFunc>, ExecuteError>
    where
        R: Resolve,
    {
        // TODO: validate
        let instance = ModuleInstance::new(self, resolver)?;
        Ok(instance)
    }

    pub fn types(&self) -> &[Functype<V>] {
        &self.types
    }

    pub fn funcs(&self) -> &[Func<V>] {
        &self.funcs
    }

    pub fn table(&self) -> Option<Tabletype> {
        self.table
    }

    pub fn mem(&self) -> Option<Memtype> {
        self.mem
    }

    pub fn globals(&self) -> &[Global] {
        &self.globals
    }

    pub fn elems(&self) -> &[Elem<V>] {
        &self.elems
    }

    pub fn datas(&self) -> &[Data<V>] {
        &self.datas
    }

    pub fn start(&self) -> Option<Funcidx> {
        self.start
    }

    pub fn imports(&self) -> &[Import<V>] {
        &self.imports
    }

    pub fn exports(&self) -> &[Export<V>] {
        &self.exports
    }
}

impl<V: VectorFactory> Debug for Module<V> {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        f.debug_struct("Module")
            .field("types", &self.types.as_ref())
            .field("funcs", &self.funcs.as_ref())
            .field("table", &self.table)
            .field("mem", &self.mem)
            .field("globals", &self.globals.as_ref())
            .field("elems", &self.elems.as_ref())
            .field("datas", &self.datas.as_ref())
            .field("start", &self.start)
            .field("imports", &self.imports.as_ref())
            .field("exports", &self.exports.as_ref())
            .finish()
    }
}

impl<V: VectorFactory> Clone for Module<V> {
    fn clone(&self) -> Self {
        Self {
            types: V::clone_vector(&self.types),
            funcs: V::clone_vector(&self.funcs),
            table: self.table,
            mem: self.mem,
            globals: V::clone_vector(&self.globals),
            elems: V::clone_vector(&self.elems),
            datas: V::clone_vector(&self.datas),
            start: self.start,
            imports: V::clone_vector(&self.imports),
            exports: V::clone_vector(&self.exports),
        }
    }
}

struct Magic;

impl Magic {
    fn decode(reader: &mut Reader) -> Result<Self, DecodeError> {
        let mut value = [0; 4];
        reader.read_exact(&mut value)?;
        if value != *b"\0asm" {
            return Err(DecodeError::InvalidMagic { value });
        }
        Ok(Self)
    }
}

struct Version;

impl Version {
    fn decode(reader: &mut Reader) -> Result<Self, DecodeError> {
        let mut value = [0; 4];
        reader.read_exact(&mut value)?;
        if value != [1, 0, 0, 0] {
            return Err(DecodeError::InvalidVersion { value });
        }
        Ok(Self)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::StdVectorFactory;

    fn decode(wasm: &[u8]) -> Module<StdVectorFactory> {
        Module::decode(wasm).expect("decode module")
    }

    #[test]
    fn decode_empty_module() {
        // (module)
        let input = [0, 97, 115, 109, 1, 0, 0, 0];
        decode(&input);
    }

    #[test]
    fn decode_add_two() {
        // (module
        //   (func (export "addTwo") (param i32 i32) (result i32)
        //     local.get 0
        //     local.get 1
        //     i32.add))
        let input = [
            0, 97, 115, 109, 1, 0, 0, 0, 1, 7, 1, 96, 2, 127, 127, 1, 127, 3, 2, 1, 0, 7, 10, 1, 6,
            97, 100, 100, 84, 119, 111, 0, 0, 10, 9, 1, 7, 0, 32, 0, 32, 1, 106, 11,
        ];
        let module = decode(&input);
        assert_eq!(1, module.exports().len());
        assert_eq!("addTwo", module.exports()[0].name.as_str());
    }
}