use walrus::{passes::gc, Module};
mod error;
mod functions;
mod state;
pub use self::error::{Error, Location};
use self::state::ProcessingState;
use crate::Function;
#[derive(Debug)]
pub struct Processor<'a> {
table_name: Option<&'a str>,
drop_fn_name: Option<(&'a str, &'a str)>,
}
impl Default for Processor<'_> {
fn default() -> Self {
Self {
table_name: Some("externrefs"),
drop_fn_name: None,
}
}
}
impl<'a> Processor<'a> {
pub fn set_ref_table(&mut self, name: impl Into<Option<&'a str>>) -> &mut Self {
self.table_name = name.into();
self
}
pub fn set_drop_fn(&mut self, module: &'a str, name: &'a str) -> &mut Self {
self.drop_fn_name = Some((module, name));
self
}
#[cfg_attr(feature = "tracing", tracing::instrument(skip_all, err))]
pub fn process(&self, module: &mut Module) -> Result<(), Error> {
let raw_section = module.customs.remove_raw(Function::CUSTOM_SECTION_NAME);
let raw_section = if let Some(section) = raw_section {
section
} else {
#[cfg(feature = "tracing")]
tracing::info!("module contains no custom section; skipping");
return Ok(());
};
let functions = Self::parse_section(&raw_section.data)?;
#[cfg(feature = "tracing")]
tracing::info!(functions.len = functions.len(), "parsed custom section");
let state = ProcessingState::new(module, self)?;
state.replace_functions(module);
state.process_functions(&functions, module)?;
gc::run(module);
Ok(())
}
fn parse_section(mut raw_section: &[u8]) -> Result<Vec<Function<'_>>, Error> {
let mut functions = vec![];
while !raw_section.is_empty() {
let next_function = Function::read_from_section(&mut raw_section)?;
functions.push(next_function);
}
Ok(functions)
}
pub fn process_bytes(&self, bytes: &[u8]) -> Result<Vec<u8>, Error> {
let mut module = Module::from_buffer(bytes).map_err(Error::Wasm)?;
self.process(&mut module)?;
Ok(module.emit_wasm())
}
}