use std::convert::TryFrom;
use std::ops::Range;
#[derive(Default)]
pub struct ModuleContext<'a> {
raw_sections: Vec<wasm_encoder::RawSection<'a>>,
imports: Vec<wasmparser::Import<'a>>,
globals: Vec<wasmparser::GlobalType>,
defined_globals_index: Option<u32>,
exports: Vec<wasmparser::Export<'a>>,
functions: Vec<u32>,
tables: Vec<wasmparser::TableType>,
memories: Vec<wasmparser::MemoryType>,
defined_memories_index: Option<u32>,
pub(crate) defined_global_exports: Option<Vec<(u32, String)>>,
pub(crate) defined_memory_exports: Option<Vec<String>>,
}
impl<'a> ModuleContext<'a> {
pub(crate) fn add_raw_section(&mut self, id: u8, range: Range<usize>, full_wasm: &'a [u8]) {
self.raw_sections.push(wasm_encoder::RawSection {
id,
data: &full_wasm[range.start..range.end],
})
}
pub(crate) fn push_imported_memory(&mut self, memory_type: wasmparser::MemoryType) {
assert!(self.defined_memories_index.is_none());
self.memories.push(memory_type);
}
pub(crate) fn push_defined_memory(&mut self, memory_type: wasmparser::MemoryType) {
if self.defined_memories_index.is_none() {
self.defined_memories_index = Some(u32::try_from(self.memories.len()).unwrap());
}
self.memories.push(memory_type);
}
pub(crate) fn push_imported_global(&mut self, global_type: wasmparser::GlobalType) {
assert!(self.defined_globals_index.is_none());
self.globals.push(global_type);
}
pub(crate) fn push_defined_global(&mut self, global_type: wasmparser::GlobalType) {
if self.defined_globals_index.is_none() {
self.defined_globals_index = Some(u32::try_from(self.globals.len()).unwrap());
}
self.globals.push(global_type);
}
pub(crate) fn push_function(&mut self, func_type: u32) {
self.functions.push(func_type);
}
pub(crate) fn push_table(&mut self, table_type: wasmparser::TableType) {
self.tables.push(table_type);
}
pub(crate) fn push_import(&mut self, import: wasmparser::Import<'a>) {
self.imports.push(import);
match import.ty {
wasmparser::TypeRef::Memory(ty) => {
self.push_imported_memory(ty);
}
wasmparser::TypeRef::Global(ty) => {
self.push_imported_global(ty);
}
wasmparser::TypeRef::Func(ty_idx) => {
self.push_function(ty_idx);
}
wasmparser::TypeRef::Table(ty) => {
self.push_table(ty);
}
wasmparser::TypeRef::Tag(_) => {
unreachable!("exceptions are unsupported; checked in validation")
}
wasmparser::TypeRef::FuncExact(_) => {
unreachable!("custom-descriptors are unsupported; checked in validation")
}
}
}
pub(crate) fn push_export(&mut self, export: wasmparser::Export<'a>) {
self.exports.push(export);
}
pub(crate) fn defined_memories_len(&self) -> usize {
self.defined_memories_index.map_or(0, |n| {
let n = usize::try_from(n).unwrap();
assert!(self.memories.len() > n);
self.memories.len() - n
})
}
pub(crate) fn defined_memories(
&self,
) -> impl Iterator<Item = (u32, wasmparser::MemoryType)> + '_ {
self.memories
.iter()
.copied()
.enumerate()
.skip(
self.defined_memories_index
.map_or(self.memories.len(), |i| usize::try_from(i).unwrap()),
)
.map(|(i, m)| (u32::try_from(i).unwrap(), m))
}
pub(crate) fn defined_globals(
&self,
) -> impl Iterator<Item = (u32, wasmparser::GlobalType, Option<&str>)> + '_ {
let mut defined_global_exports = self
.defined_global_exports
.as_ref()
.map(|v| v.as_slice())
.unwrap_or(&[])
.iter()
.peekable();
self.globals
.iter()
.copied()
.enumerate()
.skip(
self.defined_globals_index
.map_or(self.globals.len(), |i| usize::try_from(i).unwrap()),
)
.map(move |(i, g)| {
let i = u32::try_from(i).unwrap();
let name = defined_global_exports
.next_if(|(j, _)| *j == i)
.map(|(_, name)| name.as_str());
(i, g, name)
})
}
pub(crate) fn raw_sections(&self) -> &[wasm_encoder::RawSection<'a>] {
&self.raw_sections
}
pub(crate) fn imports(&self) -> &[wasmparser::Import<'a>] {
&self.imports
}
pub(crate) fn exports(&self) -> &[wasmparser::Export<'a>] {
&self.exports
}
pub(crate) fn has_wasi_initialize(&self) -> bool {
self.exports.iter().any(|e| e.name == "_initialize")
}
}