use crate::{ CORE_FUNCTION_EXACT_SORT, CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT, Encode, GlobalType, MemoryType, Section, SectionId, TableType, TagType, encode_section, }; use alloc::borrow::Cow; use alloc::vec::Vec; /// The type of an entity. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum EntityType { /// A function type. /// /// The value is an index into the types section. Function(u32), /// A table type. Table(TableType), /// A memory type. Memory(MemoryType), /// A global type. Global(GlobalType), /// A tag type. /// /// This variant is used with the exception handling proposal. Tag(TagType), /// A function exact type. /// /// The value is an index into the types section. FunctionExact(u32), } impl Encode for EntityType { fn encode(&self, sink: &mut Vec) { match self { Self::Function(f) => { sink.push(CORE_FUNCTION_SORT); f.encode(sink); } Self::FunctionExact(f) => { sink.push(CORE_FUNCTION_EXACT_SORT); f.encode(sink); } Self::Table(t) => { sink.push(CORE_TABLE_SORT); t.encode(sink); } Self::Memory(t) => { sink.push(CORE_MEMORY_SORT); t.encode(sink); } Self::Global(t) => { sink.push(CORE_GLOBAL_SORT); t.encode(sink); } Self::Tag(t) => { sink.push(CORE_TAG_SORT); t.encode(sink); } } } } impl From for EntityType { fn from(t: TableType) -> Self { Self::Table(t) } } impl From for EntityType { fn from(t: MemoryType) -> Self { Self::Memory(t) } } impl From for EntityType { fn from(t: GlobalType) -> Self { Self::Global(t) } } impl From for EntityType { fn from(t: TagType) -> Self { Self::Tag(t) } } /// An import item to be used with [`Imports::Single`]. #[derive(Clone, Debug)] pub struct Import<'a> { /// The import's module name. pub module: &'a str, /// The import's item name. pub name: &'a str, /// The import's time. pub ty: EntityType, } /// An import item to be used with [`Imports::Compact1`]. #[derive(Clone, Debug)] pub struct ImportCompact<'a> { /// The import's item name. pub name: &'a str, /// The import's type. pub ty: EntityType, } /// A single entry in the import section of a WebAssembly module, possibly containing multiple imports. #[derive(Clone, Debug)] pub enum Imports<'a> { /// A single import item. Single(Import<'a>), /// A group of imports with a common module name. Compact1 { /// The common module name. module: &'a str, /// The individual import items (name/type). items: Cow<'a, [ImportCompact<'a>]>, }, /// A group of imports with a common module name and type. Compact2 { /// The common module name. module: &'a str, /// The common import type. ty: EntityType, /// The individual import item names. names: Cow<'a, [&'a str]>, }, } /// An encoder for the import section of WebAssembly modules. /// /// # Example /// /// ```rust /// use wasm_encoder::{MemoryType, Module, ImportSection}; /// /// let mut imports = ImportSection::new(); /// imports.import( /// "env", /// "memory", /// MemoryType { /// minimum: 1, /// maximum: None, /// memory64: false, /// shared: false, /// page_size_log2: None, /// } /// ); /// /// let mut module = Module::new(); /// module.section(&imports); /// /// let bytes = module.finish(); /// ``` #[derive(Clone, Debug, Default)] pub struct ImportSection { bytes: Vec, num_added: u32, } impl ImportSection { /// Create a new import section encoder. pub fn new() -> Self { Self::default() } /// The number of imports in the section. pub fn len(&self) -> u32 { self.num_added } /// Determines if the section is empty. pub fn is_empty(&self) -> bool { self.num_added == 0 } /// Define imports in the import section. pub fn imports<'a>(&mut self, imports: Imports<'a>) -> &mut Self { match imports { Imports::Single(import) => { import.module.encode(&mut self.bytes); import.name.encode(&mut self.bytes); import.ty.encode(&mut self.bytes); } Imports::Compact1 { module, items } => { module.encode(&mut self.bytes); self.bytes.push(0x00); // empty name self.bytes.push(0x7F); items.len().encode(&mut self.bytes); for item in items.iter() { item.name.encode(&mut self.bytes); item.ty.encode(&mut self.bytes); } } Imports::Compact2 { module, ty, names } => { module.encode(&mut self.bytes); self.bytes.push(0x00); // empty name self.bytes.push(0x7E); ty.encode(&mut self.bytes); names.len().encode(&mut self.bytes); for item in names.iter() { item.encode(&mut self.bytes); } } } self.num_added += 1; self } /// Define an import in the import section. pub fn import(&mut self, module: &str, name: &str, ty: impl Into) -> &mut Self { self.imports(Imports::Single(Import { module, name, ty: ty.into(), })) } } impl Encode for ImportSection { fn encode(&self, sink: &mut Vec) { encode_section(sink, self.num_added, &self.bytes); } } impl Section for ImportSection { fn id(&self) -> u8 { SectionId::Import.into() } }