use crate::model::indices::*;
use crate::model::types::*;
use crate::model::{Expression, Name};
use crate::{ModelError, ReferenceInstruction};
use std::collections::HashMap;
use std::convert::TryFrom;
use std::mem::discriminant;
pub struct ModuleBuilder {
module: Module,
}
impl ModuleBuilder {
pub fn new() -> Self {
ModuleBuilder {
module: Module::empty(),
}
}
pub fn set_function_types(&mut self, function_types: Option<Vec<FunctionType>>) {
self.module.function_types = function_types;
}
pub fn add_function_type(
&mut self,
function_type: FunctionType,
) -> Result<TypeIndex, ModelError> {
let function_types = self.module.function_types.get_or_insert_with(Vec::new);
let index = u32::try_from(function_types.len())?;
function_types.push(function_type);
Ok(index)
}
pub fn set_functions(&mut self, functions: Option<Vec<Function>>) {
self.module.functions = functions;
}
pub fn add_function(&mut self, function: Function) -> Result<FunctionIndex, ModelError> {
let functions = self.module.functions.get_or_insert_with(Vec::new);
let imports = match &self.module.imports {
Some(imports) => imports
.iter()
.filter(|import| matches!(import.description(), ImportDescription::Function(_)))
.count(),
None => 0,
};
let index = u32::try_from(functions.len() + imports)?;
functions.push(function);
Ok(index)
}
pub fn set_tables(&mut self, tables: Option<Vec<Table>>) {
self.module.tables = tables;
}
pub fn add_table(&mut self, table: Table) -> Result<TableIndex, ModelError> {
let tables = self.module.tables.get_or_insert_with(Vec::new);
let imports = match &self.module.imports {
Some(imports) => imports
.iter()
.filter(|import| matches!(import.description(), ImportDescription::Table(_)))
.count(),
None => 0,
};
let index = u32::try_from(tables.len() + imports)?;
tables.push(table);
Ok(index)
}
pub fn set_memories(&mut self, memories: Option<Vec<Memory>>) {
self.module.memories = memories;
}
pub fn add_memory(&mut self, memory: Memory) -> Result<MemoryIndex, ModelError> {
let memories = self.module.memories.get_or_insert_with(Vec::new);
let imports = match &self.module.imports {
Some(imports) => imports
.iter()
.filter(|import| matches!(import.description(), ImportDescription::Memory(_)))
.count(),
None => 0,
};
let index = u32::try_from(memories.len() + imports)?;
memories.push(memory);
Ok(index)
}
pub fn set_globals(&mut self, globals: Option<Vec<Global>>) {
self.module.globals = globals;
}
pub fn add_global(&mut self, global: Global) -> Result<GlobalIndex, ModelError> {
let globals = self.module.globals.get_or_insert_with(Vec::new);
let imports = match &self.module.imports {
Some(imports) => imports
.iter()
.filter(|import| matches!(import.description(), ImportDescription::Global(_)))
.count(),
None => 0,
};
let index = u32::try_from(globals.len() + imports)?;
globals.push(global);
Ok(index)
}
pub fn set_elements(&mut self, elements: Option<Vec<Element>>) {
self.module.elements = elements;
}
pub fn add_element(&mut self, element: Element) -> Result<ElementIndex, ModelError> {
let elements = self.module.elements.get_or_insert_with(Vec::new);
let index = u32::try_from(elements.len())?;
elements.push(element);
Ok(index)
}
pub fn set_data(&mut self, data: Option<Vec<Data>>) {
self.module.data = data;
}
pub fn add_data(&mut self, datum: Data) -> Result<DataIndex, ModelError> {
let data = self.module.data.get_or_insert_with(Vec::new);
let index = u32::try_from(data.len())?;
data.push(datum);
Ok(index)
}
pub fn set_start(&mut self, start: Option<Start>) {
self.module.start = start;
}
pub fn set_imports(&mut self, imports: Option<Vec<Import>>) {
self.module.imports = imports;
}
pub fn add_import(&mut self, import: Import) -> Result<u32, ModelError> {
let import_discriminant = discriminant(import.description());
let imports = self.module.imports.get_or_insert_with(Vec::new);
let index = u32::try_from(
imports
.iter()
.filter(|i| discriminant(i.description()) == import_discriminant)
.count(),
)?;
imports.push(import);
Ok(index)
}
pub fn set_exports(&mut self, exports: Option<Vec<Export>>) {
self.module.exports = exports;
}
pub fn add_export(&mut self, export: Export) {
let exports = self.module.exports.get_or_insert_with(Vec::new);
exports.push(export);
}
pub fn set_custom_sections(
&mut self,
insertion_point: ModuleSection,
custom_sections: Option<Vec<Custom>>,
) {
self.module
.custom_sections
.set_custom_sections(insertion_point, custom_sections);
}
pub fn add_custom_section(&mut self, insertion_point: ModuleSection, custom_section: Custom) {
self.module
.custom_sections
.add_custom_section(insertion_point, custom_section);
}
pub fn set_data_count(&mut self, data_count: Option<u32>) {
self.module.data_count = data_count;
}
pub fn include_data_count(&mut self) {
self.module.data_count = self.module.data.as_ref().map(|v| v.len()).map(|l| l as u32);
}
pub fn function_types(&self) -> Option<&[FunctionType]> {
self.module.function_types()
}
pub fn functions(&self) -> Option<&[Function]> {
self.module.functions()
}
pub fn tables(&self) -> Option<&[Table]> {
self.module.tables()
}
pub fn memories(&self) -> Option<&[Memory]> {
self.module.memories()
}
pub fn globals(&self) -> Option<&[Global]> {
self.module.globals()
}
pub fn elements(&self) -> Option<&[Element]> {
self.module.elements()
}
pub fn data(&self) -> Option<&[Data]> {
self.module.data()
}
pub fn start(&self) -> Option<&Start> {
self.module.start()
}
pub fn imports(&self) -> Option<&[Import]> {
self.module.imports()
}
pub fn exports(&self) -> Option<&[Export]> {
self.module.exports()
}
pub fn custom_sections_at(&self, insertion_point: ModuleSection) -> Option<&[Custom]> {
self.module.custom_sections_at(insertion_point)
}
pub fn build(self) -> Module {
self.into()
}
}
impl From<ModuleBuilder> for Module {
fn from(builder: ModuleBuilder) -> Self {
builder.module
}
}
impl Default for ModuleBuilder {
fn default() -> Self {
ModuleBuilder {
module: Module::empty(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Module {
function_types: Option<Vec<FunctionType>>,
functions: Option<Vec<Function>>,
tables: Option<Vec<Table>>,
memories: Option<Vec<Memory>>,
globals: Option<Vec<Global>>,
elements: Option<Vec<Element>>,
data: Option<Vec<Data>>,
start: Option<Start>,
imports: Option<Vec<Import>>,
exports: Option<Vec<Export>>,
custom_sections: CustomSections,
data_count: Option<u32>,
}
impl Module {
pub fn builder() -> ModuleBuilder {
ModuleBuilder::new()
}
pub fn empty() -> Self {
Module {
function_types: None,
functions: None,
tables: None,
memories: None,
globals: None,
elements: None,
data: None,
start: None,
imports: None,
exports: None,
custom_sections: CustomSections::new(),
data_count: None,
}
}
pub fn function_types(&self) -> Option<&[FunctionType]> {
self.function_types.as_deref()
}
pub fn functions(&self) -> Option<&[Function]> {
self.functions.as_deref()
}
pub fn tables(&self) -> Option<&[Table]> {
self.tables.as_deref()
}
pub fn memories(&self) -> Option<&[Memory]> {
self.memories.as_deref()
}
pub fn globals(&self) -> Option<&[Global]> {
self.globals.as_deref()
}
pub fn elements(&self) -> Option<&[Element]> {
self.elements.as_deref()
}
pub fn data(&self) -> Option<&[Data]> {
self.data.as_deref()
}
pub fn start(&self) -> Option<&Start> {
self.start.as_ref()
}
pub fn imports(&self) -> Option<&[Import]> {
self.imports.as_deref()
}
pub fn exports(&self) -> Option<&[Export]> {
self.exports.as_deref()
}
pub fn custom_sections_at(&self, insertion_point: ModuleSection) -> Option<&[Custom]> {
self.custom_sections.custom_sections_at(insertion_point)
}
pub fn data_count(&self) -> Option<u32> {
self.data_count
}
}
#[derive(Clone, Debug)]
struct CustomSections {
custom_sections: HashMap<ModuleSection, Vec<Custom>>,
}
impl CustomSections {
pub fn new() -> Self {
CustomSections {
custom_sections: HashMap::new(),
}
}
pub fn custom_sections_at(&self, insertion_point: ModuleSection) -> Option<&[Custom]> {
self.custom_sections
.get(&insertion_point)
.map(Vec::as_slice)
}
pub fn set_custom_sections(
&mut self,
insertion_point: ModuleSection,
custom_sections: Option<Vec<Custom>>,
) {
match custom_sections {
Some(sections) => self.custom_sections.insert(insertion_point, sections),
None => self.custom_sections.remove(&insertion_point),
};
}
pub fn add_custom_section(&mut self, insertion_point: ModuleSection, custom_section: Custom) {
let custom_sections = self
.custom_sections
.entry(insertion_point)
.or_insert_with(Vec::new);
custom_sections.push(custom_section);
}
}
impl PartialEq for CustomSections {
fn eq(&self, other: &Self) -> bool {
self.custom_sections.len() == other.custom_sections.len()
&& self.custom_sections.keys().all(|key| {
other.custom_sections.contains_key(key)
&& self.custom_sections.get(key) == other.custom_sections.get(key)
})
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Custom {
name: Name,
bytes: Vec<u8>,
}
impl Custom {
pub fn new(name: Name, bytes: Vec<u8>) -> Self {
Custom { name, bytes }
}
pub fn name(&self) -> &Name {
&self.name
}
pub fn bytes(&self) -> &[u8] {
&self.bytes
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Function {
kind: TypeIndex,
locals: ResultType,
body: Expression,
}
impl Function {
pub fn new(kind: TypeIndex, locals: ResultType, body: Expression) -> Self {
Function { kind, locals, body }
}
pub fn kind(&self) -> TypeIndex {
self.kind
}
pub fn locals(&self) -> &ResultType {
&self.locals
}
pub fn body(&self) -> &Expression {
&self.body
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Table {
kind: TableType,
}
impl Table {
pub fn new(kind: TableType) -> Self {
Table { kind }
}
pub fn kind(&self) -> &TableType {
&self.kind
}
}
impl From<TableType> for Table {
fn from(kind: TableType) -> Self {
Table { kind }
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Memory {
kind: MemoryType,
}
impl Memory {
pub fn new(kind: MemoryType) -> Self {
Memory { kind }
}
pub fn kind(&self) -> &MemoryType {
&self.kind
}
}
impl<T> From<T> for Memory
where
T: Into<MemoryType>,
{
fn from(kind: T) -> Self {
Memory { kind: kind.into() }
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Global {
kind: GlobalType,
initializer: Expression,
}
impl Global {
pub fn new(kind: GlobalType, initializer: Expression) -> Self {
Global { kind, initializer }
}
pub fn mutable(kind: ValueType, initializer: Expression) -> Self {
Global {
kind: GlobalType::mutable(kind),
initializer,
}
}
pub fn immutable(kind: ValueType, initializer: Expression) -> Self {
Global {
kind: GlobalType::immutable(kind),
initializer,
}
}
pub fn kind(&self) -> &GlobalType {
&self.kind
}
pub fn initializer(&self) -> &Expression {
&self.initializer
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Element {
kind: ReferenceType,
mode: ElementMode,
initializers: Vec<Expression>,
}
impl Element {
pub fn new(kind: ReferenceType, mode: ElementMode, initializers: Vec<Expression>) -> Self {
Element {
kind,
mode,
initializers,
}
}
pub fn passive(kind: ReferenceType, initializers: Vec<Expression>) -> Self {
Element {
kind,
mode: ElementMode::Passive,
initializers,
}
}
pub fn active(
table: TableIndex,
offset: Expression,
kind: ReferenceType,
initializers: Vec<Expression>,
) -> Self {
Element {
kind,
mode: ElementMode::Active(table, offset),
initializers,
}
}
pub fn declarative(kind: ReferenceType, initializers: Vec<Expression>) -> Self {
Element {
kind,
mode: ElementMode::Declarative,
initializers,
}
}
pub fn kind(&self) -> ReferenceType {
self.kind
}
pub fn initializers(&self) -> &[Expression] {
&self.initializers
}
pub fn mode(&self) -> &ElementMode {
&self.mode
}
}
pub trait ElementInitializer {
fn to_initializers(self) -> Vec<Expression>;
}
impl ElementInitializer for Vec<Expression> {
fn to_initializers(self) -> Vec<Expression> {
self
}
}
impl ElementInitializer for Vec<FunctionIndex> {
fn to_initializers(self) -> Vec<Expression> {
self.into_iter()
.map(|function| Expression::new(vec![ReferenceInstruction::Function(function).into()]))
.collect()
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ElementMode {
Passive,
Active(TableIndex, Expression),
Declarative,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Data {
mode: DataMode,
initializer: Vec<u8>,
}
impl Data {
pub fn new(mode: DataMode, initializer: Vec<u8>) -> Self {
Data { mode, initializer }
}
pub fn passive(initializer: Vec<u8>) -> Self {
Data {
mode: DataMode::Passive,
initializer,
}
}
pub fn active(memory: MemoryIndex, offset: Expression, initializer: Vec<u8>) -> Self {
Data {
mode: DataMode::Active(memory, offset),
initializer,
}
}
pub fn mode(&self) -> &DataMode {
&self.mode
}
pub fn initializer(&self) -> &[u8] {
&self.initializer
}
pub fn len(&self) -> usize {
self.initializer.len()
}
pub fn is_empty(&self) -> bool {
self.initializer.is_empty()
}
}
impl From<Vec<u8>> for Data {
fn from(initializer: Vec<u8>) -> Self {
Data {
mode: DataMode::Passive,
initializer,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum DataMode {
Passive,
Active(MemoryIndex, Expression),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Start {
function: FunctionIndex,
}
impl Start {
pub fn new(function: FunctionIndex) -> Self {
Start { function }
}
pub fn function(&self) -> FunctionIndex {
self.function
}
}
impl From<u32> for Start {
fn from(function: u32) -> Self {
Start { function }
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Export {
name: Name,
description: ExportDescription,
}
impl Export {
pub fn new(name: Name, description: ExportDescription) -> Self {
Export { name, description }
}
pub fn table(name: Name, table: TableIndex) -> Self {
Export {
name,
description: ExportDescription::Table(table),
}
}
pub fn memory(name: Name, memory: MemoryIndex) -> Self {
Export {
name,
description: ExportDescription::Memory(memory),
}
}
pub fn function(name: Name, function: FunctionIndex) -> Self {
Export {
name,
description: ExportDescription::Function(function),
}
}
pub fn global(name: Name, global: GlobalIndex) -> Self {
Export {
name,
description: ExportDescription::Global(global),
}
}
pub fn name(&self) -> &Name {
&self.name
}
pub fn description(&self) -> &ExportDescription {
&self.description
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ExportDescription {
Function(FunctionIndex),
Table(TableIndex),
Memory(MemoryIndex),
Global(GlobalIndex),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Import {
module: Name,
name: Name,
description: ImportDescription,
}
impl Import {
pub fn new(module: Name, name: Name, description: ImportDescription) -> Self {
Import {
module,
name,
description,
}
}
pub fn table(module: Name, name: Name, table_kind: TableType) -> Self {
Import {
module,
name,
description: ImportDescription::Table(table_kind),
}
}
pub fn memory(module: Name, name: Name, memory_kind: MemoryType) -> Self {
Import {
module,
name,
description: ImportDescription::Memory(memory_kind),
}
}
pub fn function(module: Name, name: Name, function_kind: TypeIndex) -> Self {
Import {
module,
name,
description: ImportDescription::Function(function_kind),
}
}
pub fn global(module: Name, name: Name, global_kind: GlobalType) -> Self {
Import {
module,
name,
description: ImportDescription::Global(global_kind),
}
}
pub fn module(&self) -> &Name {
&self.module
}
pub fn name(&self) -> &Name {
&self.name
}
pub fn description(&self) -> &ImportDescription {
&self.description
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ImportDescription {
Function(TypeIndex),
Table(TableType),
Memory(MemoryType),
Global(GlobalType),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ModuleSection {
Custom = 0,
Type,
Import,
Function,
Table,
Memory,
Global,
Export,
Start,
Element,
Code,
Data,
DataCount,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn module_equality_when_empty() {
assert_eq!(Module::builder().build(), Module::empty());
}
#[test]
fn module_equality_for_custom_sections() {
let mut builder = Module::builder();
builder.add_custom_section(
ModuleSection::Data,
Custom::new("version".into(), b"0.0.1".to_vec()),
);
let module = builder.build();
assert_eq!(module, module.clone());
assert_ne!(module, Module::empty());
}
#[test]
fn module_equality_not_same_custom_sections() {
let mut builder = Module::builder();
builder.add_custom_section(
ModuleSection::Data,
Custom::new("version".into(), b"0.0.1".to_vec()),
);
let mut other_builder = Module::builder();
other_builder.add_custom_section(
ModuleSection::Export,
Custom::new("version".into(), b"0.0.1".to_vec()),
);
let module = builder.build();
let other_module = other_builder.build();
assert_ne!(module, other_module);
}
}