1use crate::entity::{EntityRef, PrimaryMap};
8use crate::{
9 CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, FunctionIndex, FunctionType,
10 GlobalIndex, GlobalInit, GlobalType, ImportIndex, LocalFunctionIndex, LocalGlobalIndex,
11 LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, OwnedTableInitializer,
12 SignatureIndex, TableIndex, TableType,
13};
14use indexmap::IndexMap;
15use std::collections::BTreeMap;
16use std::fmt;
17use std::sync::Arc;
18use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
19
20#[derive(Debug, Clone, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
21pub struct ModuleId {
22 id: usize,
23}
24
25impl ModuleId {
26 pub fn id(&self) -> String {
27 format!("{}", &self.id)
28 }
29}
30
31impl Default for ModuleId {
32 fn default() -> Self {
33 static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
34 Self { id: NEXT_ID.fetch_add(1, SeqCst) }
35 }
36}
37
38#[derive(
40 Debug, Copy, Clone, Default, PartialEq, Eq, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive,
41)]
42pub struct ImportCounts {
43 pub functions: u32,
45
46 pub tables: u32,
48
49 pub memories: u32,
51
52 pub globals: u32,
54}
55
56impl ImportCounts {
57 fn make_local<R: EntityRef, I: EntityRef>(idx: I, imports: u32) -> Result<R, I> {
58 EntityRef::index(idx).checked_sub(imports as _).map(R::new).ok_or(idx)
59 }
60
61 pub fn local_function_index(
63 &self,
64 idx: FunctionIndex,
65 ) -> Result<LocalFunctionIndex, FunctionIndex> {
66 Self::make_local(idx, self.functions)
67 }
68
69 pub fn local_table_index(&self, idx: TableIndex) -> Result<LocalTableIndex, TableIndex> {
71 Self::make_local(idx, self.tables)
72 }
73
74 pub fn local_memory_index(&self, idx: MemoryIndex) -> Result<LocalMemoryIndex, MemoryIndex> {
76 Self::make_local(idx, self.memories)
77 }
78
79 pub fn local_global_index(&self, idx: GlobalIndex) -> Result<LocalGlobalIndex, GlobalIndex> {
81 Self::make_local(idx, self.globals)
82 }
83
84 fn make_index<R: EntityRef, I: EntityRef>(idx: I, imports: u32) -> R {
85 let imports = imports as usize;
86 R::new(idx.index() + imports)
87 }
88
89 pub fn function_index(&self, idx: LocalFunctionIndex) -> FunctionIndex {
91 Self::make_index(idx, self.functions)
92 }
93
94 pub fn table_index(&self, idx: LocalTableIndex) -> TableIndex {
96 Self::make_index(idx, self.tables)
97 }
98
99 pub fn memory_index(&self, idx: LocalMemoryIndex) -> MemoryIndex {
101 Self::make_index(idx, self.memories)
102 }
103
104 pub fn global_index(&self, idx: LocalGlobalIndex) -> GlobalIndex {
106 Self::make_index(idx, self.globals)
107 }
108}
109
110#[derive(Debug, Clone, Default, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
113pub struct ModuleInfo {
114 #[rkyv(with = rkyv::with::Skip)]
119 pub id: ModuleId,
120
121 pub name: Option<String>,
123
124 pub imports: IndexMap<(String, String, u32), ImportIndex>,
130
131 pub exports: IndexMap<String, ExportIndex>,
133
134 pub start_function: Option<FunctionIndex>,
136
137 pub table_initializers: Vec<OwnedTableInitializer>,
139
140 pub passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
142
143 pub passive_data: BTreeMap<DataIndex, Arc<[u8]>>,
145
146 pub global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
148
149 pub function_names: BTreeMap<FunctionIndex, String>,
151
152 pub signatures: PrimaryMap<SignatureIndex, FunctionType>,
154
155 pub functions: PrimaryMap<FunctionIndex, SignatureIndex>,
157
158 pub tables: PrimaryMap<TableIndex, TableType>,
160
161 pub memories: PrimaryMap<MemoryIndex, MemoryType>,
163
164 pub globals: PrimaryMap<GlobalIndex, GlobalType>,
166
167 pub custom_sections: IndexMap<String, CustomSectionIndex>,
169
170 pub custom_sections_data: PrimaryMap<CustomSectionIndex, Arc<[u8]>>,
172
173 pub import_counts: ImportCounts,
175}
176
177impl PartialEq for ModuleInfo {
179 fn eq(&self, other: &Self) -> bool {
180 self.name == other.name
181 && self.imports == other.imports
182 && self.exports == other.exports
183 && self.start_function == other.start_function
184 && self.table_initializers == other.table_initializers
185 && self.passive_elements == other.passive_elements
186 && self.passive_data == other.passive_data
187 && self.global_initializers == other.global_initializers
188 && self.function_names == other.function_names
189 && self.signatures == other.signatures
190 && self.functions == other.functions
191 && self.tables == other.tables
192 && self.memories == other.memories
193 && self.globals == other.globals
194 && self.custom_sections == other.custom_sections
195 && self.custom_sections_data == other.custom_sections_data
196 && self.import_counts == other.import_counts
197 }
198}
199
200impl Eq for ModuleInfo {}
201
202impl ModuleInfo {
203 pub fn new() -> Self {
205 Default::default()
206 }
207
208 pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
210 self.passive_elements.get(&index).map(|es| &**es)
211 }
212
213 pub fn exported_signatures(&self) -> Vec<FunctionType> {
215 self.exports
216 .iter()
217 .filter_map(|(_name, export_index)| match export_index {
218 ExportIndex::Function(i) => {
219 let signature = self.functions.get(*i).unwrap();
220 let func_type = self.signatures.get(*signature).unwrap();
221 Some(func_type.clone())
222 }
223 _ => None,
224 })
225 .collect::<Vec<FunctionType>>()
226 }
227
228 pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Arc<[u8]>> + 'a {
230 self.custom_sections.iter().filter_map(move |(section_name, section_index)| {
231 if name != section_name {
232 return None;
233 }
234 Some(self.custom_sections_data[*section_index].clone())
235 })
236 }
237
238 pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
240 self.import_counts.function_index(local_func)
241 }
242
243 pub fn local_func_index(&self, func: FunctionIndex) -> Option<LocalFunctionIndex> {
246 self.import_counts.local_function_index(func).ok()
247 }
248
249 pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
251 self.local_func_index(index).is_none()
252 }
253
254 pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
256 self.import_counts.table_index(local_table)
257 }
258
259 pub fn local_table_index(&self, table: TableIndex) -> Option<LocalTableIndex> {
262 self.import_counts.local_table_index(table).ok()
263 }
264
265 pub fn is_imported_table(&self, index: TableIndex) -> bool {
267 self.local_table_index(index).is_none()
268 }
269
270 pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
272 self.import_counts.memory_index(local_memory)
273 }
274
275 pub fn local_memory_index(&self, memory: MemoryIndex) -> Option<LocalMemoryIndex> {
278 self.import_counts.local_memory_index(memory).ok()
279 }
280
281 pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
283 self.local_memory_index(index).is_none()
284 }
285
286 pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
288 self.import_counts.global_index(local_global)
289 }
290
291 pub fn local_global_index(&self, global: GlobalIndex) -> Option<LocalGlobalIndex> {
294 self.import_counts.local_global_index(global).ok()
295 }
296
297 pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
299 self.local_global_index(index).is_none()
300 }
301
302 pub fn name(&self) -> String {
304 match self.name {
305 Some(ref name) => name.to_string(),
306 None => "<module>".to_string(),
307 }
308 }
309
310 pub fn imported_function_types<'a>(&'a self) -> impl Iterator<Item = FunctionType> + 'a {
312 self.functions
313 .values()
314 .take(self.import_counts.functions as usize)
315 .map(move |sig_index| self.signatures[*sig_index].clone())
316 }
317}
318
319impl fmt::Display for ModuleInfo {
320 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
321 write!(f, "{}", self.name())
322 }
323}