use crate::entity::{EntityRef, PrimaryMap};
use crate::ArchivableIndexMap;
use crate::{
CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, FunctionIndex, FunctionType,
GlobalIndex, GlobalInit, GlobalType, ImportIndex, LocalFunctionIndex, LocalGlobalIndex,
LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, OwnedTableInitializer,
SignatureIndex, TableIndex, TableType,
};
use indexmap::IndexMap;
use rkyv::{
de::SharedDeserializeRegistry, ser::ScratchSpace, ser::Serializer,
ser::SharedSerializeRegistry, Archive, Archived, Fallible,
};
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::fmt;
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use std::sync::Arc;
#[derive(Debug, Clone, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
pub struct ModuleId {
id: usize,
}
impl ModuleId {
pub fn id(&self) -> String {
format!("{}", &self.id)
}
}
impl Default for ModuleId {
fn default() -> Self {
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
Self {
id: NEXT_ID.fetch_add(1, SeqCst),
}
}
}
#[derive(
Debug, Copy, Clone, Default, PartialEq, Eq, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive,
)]
#[archive(as = "Self")]
pub struct ImportCounts {
pub functions: u32,
pub tables: u32,
pub memories: u32,
pub globals: u32,
}
impl ImportCounts {
fn make_local<R: EntityRef, I: EntityRef>(idx: I, imports: u32) -> Result<R, I> {
EntityRef::index(idx)
.checked_sub(imports as _)
.map(R::new)
.ok_or(idx)
}
pub fn local_function_index(
&self,
idx: FunctionIndex,
) -> Result<LocalFunctionIndex, FunctionIndex> {
Self::make_local(idx, self.functions)
}
pub fn local_table_index(&self, idx: TableIndex) -> Result<LocalTableIndex, TableIndex> {
Self::make_local(idx, self.tables)
}
pub fn local_memory_index(&self, idx: MemoryIndex) -> Result<LocalMemoryIndex, MemoryIndex> {
Self::make_local(idx, self.memories)
}
pub fn local_global_index(&self, idx: GlobalIndex) -> Result<LocalGlobalIndex, GlobalIndex> {
Self::make_local(idx, self.globals)
}
fn make_index<R: EntityRef, I: EntityRef>(idx: I, imports: u32) -> R {
let imports = imports as usize;
R::new(idx.index() + imports)
}
pub fn function_index(&self, idx: LocalFunctionIndex) -> FunctionIndex {
Self::make_index(idx, self.functions)
}
pub fn table_index(&self, idx: LocalTableIndex) -> TableIndex {
Self::make_index(idx, self.tables)
}
pub fn memory_index(&self, idx: LocalMemoryIndex) -> MemoryIndex {
Self::make_index(idx, self.memories)
}
pub fn global_index(&self, idx: LocalGlobalIndex) -> GlobalIndex {
Self::make_index(idx, self.globals)
}
}
#[derive(Debug, Clone, Default)]
pub struct ModuleInfo {
pub id: ModuleId,
pub name: Option<String>,
pub imports: IndexMap<(String, String, u32), ImportIndex>,
pub exports: IndexMap<String, ExportIndex>,
pub start_function: Option<FunctionIndex>,
pub table_initializers: Vec<OwnedTableInitializer>,
pub passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
pub passive_data: BTreeMap<DataIndex, Arc<[u8]>>,
pub global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
pub function_names: HashMap<FunctionIndex, String>,
pub signatures: PrimaryMap<SignatureIndex, FunctionType>,
pub functions: PrimaryMap<FunctionIndex, SignatureIndex>,
pub tables: PrimaryMap<TableIndex, TableType>,
pub memories: PrimaryMap<MemoryIndex, MemoryType>,
pub globals: PrimaryMap<GlobalIndex, GlobalType>,
pub custom_sections: IndexMap<String, CustomSectionIndex>,
pub custom_sections_data: PrimaryMap<CustomSectionIndex, Arc<[u8]>>,
pub import_counts: ImportCounts,
}
#[derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
pub struct ArchivableModuleInfo {
pub name: Option<String>,
pub imports: ArchivableIndexMap<(String, String, u32), ImportIndex>,
pub exports: ArchivableIndexMap<String, ExportIndex>,
pub start_function: Option<FunctionIndex>,
pub table_initializers: Vec<OwnedTableInitializer>,
pub passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
pub passive_data: BTreeMap<DataIndex, Arc<[u8]>>,
pub global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
pub function_names: BTreeMap<FunctionIndex, String>,
pub signatures: PrimaryMap<SignatureIndex, FunctionType>,
pub functions: PrimaryMap<FunctionIndex, SignatureIndex>,
pub tables: PrimaryMap<TableIndex, TableType>,
pub memories: PrimaryMap<MemoryIndex, MemoryType>,
pub globals: PrimaryMap<GlobalIndex, GlobalType>,
pub custom_sections: ArchivableIndexMap<String, CustomSectionIndex>,
pub custom_sections_data: PrimaryMap<CustomSectionIndex, Arc<[u8]>>,
pub import_counts: ImportCounts,
}
impl From<ModuleInfo> for ArchivableModuleInfo {
fn from(it: ModuleInfo) -> ArchivableModuleInfo {
ArchivableModuleInfo {
name: it.name,
imports: ArchivableIndexMap::from(it.imports),
exports: ArchivableIndexMap::from(it.exports),
start_function: it.start_function,
table_initializers: it.table_initializers,
passive_elements: it.passive_elements.into_iter().collect(),
passive_data: it.passive_data.into_iter().collect(),
global_initializers: it.global_initializers,
function_names: it.function_names.into_iter().collect(),
signatures: it.signatures,
functions: it.functions,
tables: it.tables,
memories: it.memories,
globals: it.globals,
custom_sections: ArchivableIndexMap::from(it.custom_sections),
custom_sections_data: it.custom_sections_data,
import_counts: it.import_counts,
}
}
}
impl From<ArchivableModuleInfo> for ModuleInfo {
fn from(it: ArchivableModuleInfo) -> ModuleInfo {
ModuleInfo {
id: Default::default(),
name: it.name,
imports: it.imports.into(),
exports: it.exports.into(),
start_function: it.start_function,
table_initializers: it.table_initializers,
passive_elements: it.passive_elements.into_iter().collect(),
passive_data: it.passive_data.into_iter().collect(),
global_initializers: it.global_initializers,
function_names: it.function_names.into_iter().collect(),
signatures: it.signatures,
functions: it.functions,
tables: it.tables,
memories: it.memories,
globals: it.globals,
custom_sections: it.custom_sections.into(),
custom_sections_data: it.custom_sections_data,
import_counts: it.import_counts,
}
}
}
impl From<&ModuleInfo> for ArchivableModuleInfo {
fn from(it: &ModuleInfo) -> ArchivableModuleInfo {
ArchivableModuleInfo::from(it.clone())
}
}
impl Archive for ModuleInfo {
type Archived = <ArchivableModuleInfo as Archive>::Archived;
type Resolver = <ArchivableModuleInfo as Archive>::Resolver;
unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) {
ArchivableModuleInfo::from(self).resolve(pos, resolver, out)
}
}
impl<S: Serializer + SharedSerializeRegistry + ScratchSpace + ?Sized> rkyv::Serialize<S>
for ModuleInfo
{
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
ArchivableModuleInfo::from(self).serialize(serializer)
}
}
impl<D: Fallible + ?Sized + SharedDeserializeRegistry> rkyv::Deserialize<ModuleInfo, D>
for Archived<ModuleInfo>
{
fn deserialize(&self, deserializer: &mut D) -> Result<ModuleInfo, D::Error> {
let r: ArchivableModuleInfo =
rkyv::Deserialize::<ArchivableModuleInfo, D>::deserialize(self, deserializer)?;
Ok(ModuleInfo::from(r))
}
}
impl PartialEq for ModuleInfo {
fn eq(&self, other: &ModuleInfo) -> bool {
self.name == other.name
&& self.imports == other.imports
&& self.exports == other.exports
&& self.start_function == other.start_function
&& self.table_initializers == other.table_initializers
&& self.passive_elements == other.passive_elements
&& self.passive_data == other.passive_data
&& self.global_initializers == other.global_initializers
&& self.function_names == other.function_names
&& self.signatures == other.signatures
&& self.functions == other.functions
&& self.tables == other.tables
&& self.memories == other.memories
&& self.globals == other.globals
&& self.custom_sections == other.custom_sections
&& self.custom_sections_data == other.custom_sections_data
&& self.import_counts == other.import_counts
}
}
impl Eq for ModuleInfo {}
impl ModuleInfo {
pub fn new() -> Self {
Default::default()
}
pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
self.passive_elements.get(&index).map(|es| &**es)
}
pub fn exported_signatures(&self) -> Vec<FunctionType> {
self.exports
.iter()
.filter_map(|(_name, export_index)| match export_index {
ExportIndex::Function(i) => {
let signature = self.functions.get(*i).unwrap();
let func_type = self.signatures.get(*signature).unwrap();
Some(func_type.clone())
}
_ => None,
})
.collect::<Vec<FunctionType>>()
}
pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Arc<[u8]>> + 'a {
self.custom_sections
.iter()
.filter_map(move |(section_name, section_index)| {
if name != section_name {
return None;
}
Some(self.custom_sections_data[*section_index].clone())
})
}
pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
self.import_counts.function_index(local_func)
}
pub fn local_func_index(&self, func: FunctionIndex) -> Option<LocalFunctionIndex> {
self.import_counts.local_function_index(func).ok()
}
pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
self.local_func_index(index).is_none()
}
pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
self.import_counts.table_index(local_table)
}
pub fn local_table_index(&self, table: TableIndex) -> Option<LocalTableIndex> {
self.import_counts.local_table_index(table).ok()
}
pub fn is_imported_table(&self, index: TableIndex) -> bool {
self.local_table_index(index).is_none()
}
pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
self.import_counts.memory_index(local_memory)
}
pub fn local_memory_index(&self, memory: MemoryIndex) -> Option<LocalMemoryIndex> {
self.import_counts.local_memory_index(memory).ok()
}
pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
self.local_memory_index(index).is_none()
}
pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
self.import_counts.global_index(local_global)
}
pub fn local_global_index(&self, global: GlobalIndex) -> Option<LocalGlobalIndex> {
self.import_counts.local_global_index(global).ok()
}
pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
self.local_global_index(index).is_none()
}
pub fn name(&self) -> String {
match self.name {
Some(ref name) => name.to_string(),
None => "<module>".to_string(),
}
}
pub fn imported_function_types<'a>(&'a self) -> impl Iterator<Item = FunctionType> + 'a {
self.functions
.values()
.take(self.import_counts.functions as usize)
.map(move |sig_index| self.signatures[*sig_index].clone())
}
}
impl fmt::Display for ModuleInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}