use crate::emit::{Emit, EmitContext, Section};
use crate::parse::IndicesToIds;
use crate::tombstone_arena::{Id, Tombstone, TombstoneArena};
use crate::{FunctionId, GlobalId, MemoryId, Module, Result, TableId};
pub type ExportId = Id<Export>;
#[derive(Clone, Debug)]
pub struct Export {
id: ExportId,
pub name: String,
pub item: ExportItem,
}
impl Tombstone for Export {
fn on_delete(&mut self) {
self.name = String::new();
}
}
impl Export {
pub fn id(&self) -> ExportId {
self.id
}
}
#[derive(Copy, Clone, Debug)]
pub enum ExportItem {
Function(FunctionId),
Table(TableId),
Memory(MemoryId),
Global(GlobalId),
}
#[derive(Debug, Default)]
pub struct ModuleExports {
arena: TombstoneArena<Export>,
}
impl ModuleExports {
pub fn get(&self, id: ExportId) -> &Export {
&self.arena[id]
}
pub fn get_mut(&mut self, id: ExportId) -> &mut Export {
&mut self.arena[id]
}
pub fn delete(&mut self, id: ExportId) {
self.arena.delete(id);
}
pub fn iter(&self) -> impl Iterator<Item = &Export> {
self.arena.iter().map(|(_, f)| f)
}
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Export> {
self.arena.iter_mut().map(|(_, f)| f)
}
pub fn add(&mut self, name: &str, item: impl Into<ExportItem>) -> ExportId {
self.arena.alloc_with_id(|id| Export {
id,
name: name.to_string(),
item: item.into(),
})
}
#[doc(hidden)]
#[deprecated(note = "Use `ModuleExports::delete` instead")]
pub fn remove_root(&mut self, id: ExportId) {
self.delete(id);
}
}
impl Module {
pub(crate) fn parse_exports(
&mut self,
section: wasmparser::ExportSectionReader,
ids: &IndicesToIds,
) -> Result<()> {
log::debug!("parse export section");
use wasmparser::ExternalKind::*;
for entry in section {
let entry = entry?;
let item = match entry.kind {
Function => ExportItem::Function(ids.get_func(entry.index)?),
Table => ExportItem::Table(ids.get_table(entry.index)?),
Memory => ExportItem::Memory(ids.get_memory(entry.index)?),
Global => ExportItem::Global(ids.get_global(entry.index)?),
};
self.exports.arena.alloc_with_id(|id| Export {
id,
name: entry.field.to_string(),
item,
});
}
Ok(())
}
}
impl Emit for ModuleExports {
fn emit(&self, cx: &mut EmitContext) {
log::debug!("emit export section");
let count = self.iter().count();
if count == 0 {
return;
}
let mut cx = cx.start_section(Section::Export);
cx.encoder.usize(count);
for export in self.iter() {
cx.encoder.str(&export.name);
match export.item {
ExportItem::Function(id) => {
let index = cx.indices.get_func_index(id);
cx.encoder.byte(0x00);
cx.encoder.u32(index);
}
ExportItem::Table(id) => {
let index = cx.indices.get_table_index(id);
cx.encoder.byte(0x01);
cx.encoder.u32(index);
}
ExportItem::Memory(id) => {
let index = cx.indices.get_memory_index(id);
cx.encoder.byte(0x02);
cx.encoder.u32(index);
}
ExportItem::Global(id) => {
let index = cx.indices.get_global_index(id);
cx.encoder.byte(0x03);
cx.encoder.u32(index);
}
}
}
}
}
impl From<MemoryId> for ExportItem {
fn from(id: MemoryId) -> ExportItem {
ExportItem::Memory(id)
}
}
impl From<FunctionId> for ExportItem {
fn from(id: FunctionId) -> ExportItem {
ExportItem::Function(id)
}
}
impl From<GlobalId> for ExportItem {
fn from(id: GlobalId) -> ExportItem {
ExportItem::Global(id)
}
}
impl From<TableId> for ExportItem {
fn from(id: TableId) -> ExportItem {
ExportItem::Table(id)
}
}