1use crate::entity::{EntityRef, PrimaryMap};
8use crate::{
9 CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, ExportType, ExternType, FunctionIndex,
10 FunctionType, GlobalIndex, GlobalInit, GlobalType, ImportIndex, ImportType, LocalFunctionIndex,
11 LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, ModuleHash,
12 SignatureIndex, TableIndex, TableInitializer, TableType,
13};
14
15use indexmap::IndexMap;
16use rkyv::rancor::{Fallible, Source, Trace};
17use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
18#[cfg(feature = "enable-serde")]
19use serde::{Deserialize, Serialize};
20use std::collections::BTreeMap;
21use std::collections::HashMap;
22use std::fmt;
23use std::iter::ExactSizeIterator;
24use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
25
26#[derive(Debug, Clone, RkyvSerialize, RkyvDeserialize, Archive)]
27#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
28#[rkyv(derive(Debug))]
29pub struct ModuleId {
30 id: usize,
31}
32
33impl ModuleId {
34 pub fn id(&self) -> String {
35 format!("{}", &self.id)
36 }
37}
38
39impl Default for ModuleId {
40 fn default() -> Self {
41 static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
42 Self {
43 id: NEXT_ID.fetch_add(1, SeqCst),
44 }
45 }
46}
47
48#[derive(Debug, Hash, Eq, PartialEq, Clone, Default, RkyvSerialize, RkyvDeserialize, Archive)]
50#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
51#[rkyv(derive(PartialOrd, Ord, PartialEq, Eq, Hash, Debug))]
52pub struct ImportKey {
53 pub module: String,
55 pub field: String,
57 pub import_idx: u32,
59}
60
61impl From<(String, String, u32)> for ImportKey {
62 fn from((module, field, import_idx): (String, String, u32)) -> Self {
63 Self {
64 module,
65 field,
66 import_idx,
67 }
68 }
69}
70
71#[cfg(feature = "enable-serde")]
72mod serde_imports {
73
74 use crate::ImportIndex;
75 use crate::ImportKey;
76 use indexmap::IndexMap;
77 use serde::{Deserialize, Deserializer, Serialize, Serializer};
78
79 type InitialType = IndexMap<ImportKey, ImportIndex>;
80 type SerializedType = Vec<(ImportKey, ImportIndex)>;
81 pub fn serialize<S: Serializer>(s: &InitialType, serializer: S) -> Result<S::Ok, S::Error> {
84 let vec: SerializedType = s
85 .iter()
86 .map(|(a, b)| (a.clone(), b.clone()))
87 .collect::<Vec<_>>();
88 vec.serialize(serializer)
89 }
90
91 pub fn deserialize<'de, D: Deserializer<'de>>(
92 deserializer: D,
93 ) -> Result<InitialType, D::Error> {
94 let serialized = <SerializedType as Deserialize>::deserialize(deserializer)?;
95 Ok(serialized.into_iter().collect())
96 }
97}
98
99#[derive(Debug, Clone, Default)]
106#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
107#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
108pub struct ModuleInfo {
109 #[cfg_attr(feature = "enable-serde", serde(skip_serializing, skip_deserializing))]
116 pub id: ModuleId,
117
118 pub hash: Option<ModuleHash>,
120
121 pub name: Option<String>,
123
124 #[cfg_attr(feature = "enable-serde", serde(with = "serde_imports"))]
130 pub imports: IndexMap<ImportKey, ImportIndex>,
131
132 pub exports: IndexMap<String, ExportIndex>,
134
135 pub start_function: Option<FunctionIndex>,
137
138 pub table_initializers: Vec<TableInitializer>,
140
141 pub passive_elements: HashMap<ElemIndex, Box<[FunctionIndex]>>,
143
144 pub passive_data: HashMap<DataIndex, Box<[u8]>>,
146
147 pub global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
149
150 pub function_names: HashMap<FunctionIndex, String>,
152
153 pub signatures: PrimaryMap<SignatureIndex, FunctionType>,
155
156 pub functions: PrimaryMap<FunctionIndex, SignatureIndex>,
158
159 pub tables: PrimaryMap<TableIndex, TableType>,
161
162 pub memories: PrimaryMap<MemoryIndex, MemoryType>,
164
165 pub globals: PrimaryMap<GlobalIndex, GlobalType>,
167
168 pub custom_sections: IndexMap<String, CustomSectionIndex>,
170
171 pub custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
173
174 pub num_imported_functions: usize,
176
177 pub num_imported_tables: usize,
179
180 pub num_imported_memories: usize,
182
183 pub num_imported_globals: usize,
185}
186
187#[derive(Debug, RkyvSerialize, RkyvDeserialize, Archive)]
189#[rkyv(derive(Debug))]
190pub struct ArchivableModuleInfo {
191 name: Option<String>,
192 hash: Option<ModuleHash>,
193 imports: IndexMap<ImportKey, ImportIndex>,
194 exports: IndexMap<String, ExportIndex>,
195 start_function: Option<FunctionIndex>,
196 table_initializers: Vec<TableInitializer>,
197 passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
198 passive_data: BTreeMap<DataIndex, Box<[u8]>>,
199 global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
200 function_names: BTreeMap<FunctionIndex, String>,
201 signatures: PrimaryMap<SignatureIndex, FunctionType>,
202 functions: PrimaryMap<FunctionIndex, SignatureIndex>,
203 tables: PrimaryMap<TableIndex, TableType>,
204 memories: PrimaryMap<MemoryIndex, MemoryType>,
205 globals: PrimaryMap<GlobalIndex, GlobalType>,
206 custom_sections: IndexMap<String, CustomSectionIndex>,
207 custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
208 num_imported_functions: usize,
209 num_imported_tables: usize,
210 num_imported_memories: usize,
211 num_imported_globals: usize,
212}
213
214impl From<ModuleInfo> for ArchivableModuleInfo {
215 fn from(it: ModuleInfo) -> Self {
216 Self {
217 name: it.name,
218 hash: it.hash,
219 imports: it.imports,
220 exports: it.exports,
221 start_function: it.start_function,
222 table_initializers: it.table_initializers,
223 passive_elements: it.passive_elements.into_iter().collect(),
224 passive_data: it.passive_data.into_iter().collect(),
225 global_initializers: it.global_initializers,
226 function_names: it.function_names.into_iter().collect(),
227 signatures: it.signatures,
228 functions: it.functions,
229 tables: it.tables,
230 memories: it.memories,
231 globals: it.globals,
232 custom_sections: it.custom_sections,
233 custom_sections_data: it.custom_sections_data,
234 num_imported_functions: it.num_imported_functions,
235 num_imported_tables: it.num_imported_tables,
236 num_imported_memories: it.num_imported_memories,
237 num_imported_globals: it.num_imported_globals,
238 }
239 }
240}
241
242impl From<ArchivableModuleInfo> for ModuleInfo {
243 fn from(it: ArchivableModuleInfo) -> Self {
244 Self {
245 id: Default::default(),
246 name: it.name,
247 hash: it.hash,
248 imports: it.imports,
249 exports: it.exports,
250 start_function: it.start_function,
251 table_initializers: it.table_initializers,
252 passive_elements: it.passive_elements.into_iter().collect(),
253 passive_data: it.passive_data.into_iter().collect(),
254 global_initializers: it.global_initializers,
255 function_names: it.function_names.into_iter().collect(),
256 signatures: it.signatures,
257 functions: it.functions,
258 tables: it.tables,
259 memories: it.memories,
260 globals: it.globals,
261 custom_sections: it.custom_sections,
262 custom_sections_data: it.custom_sections_data,
263 num_imported_functions: it.num_imported_functions,
264 num_imported_tables: it.num_imported_tables,
265 num_imported_memories: it.num_imported_memories,
266 num_imported_globals: it.num_imported_globals,
267 }
268 }
269}
270
271impl From<&ModuleInfo> for ArchivableModuleInfo {
272 fn from(it: &ModuleInfo) -> Self {
273 Self::from(it.clone())
274 }
275}
276
277impl Archive for ModuleInfo {
278 type Archived = <ArchivableModuleInfo as Archive>::Archived;
279 type Resolver = <ArchivableModuleInfo as Archive>::Resolver;
280
281 fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
282 ArchivableModuleInfo::from(self).resolve(resolver, out)
283 }
284}
285
286impl<S: rkyv::ser::Allocator + rkyv::ser::Writer + Fallible + ?Sized> RkyvSerialize<S>
287 for ModuleInfo
288where
289 <S as Fallible>::Error: rkyv::rancor::Source + rkyv::rancor::Trace,
290{
291 fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
292 ArchivableModuleInfo::from(self).serialize(serializer)
293 }
294}
295
296impl<D: Fallible + ?Sized> RkyvDeserialize<ModuleInfo, D> for ArchivedArchivableModuleInfo
297where
298 D::Error: Source + Trace,
299{
300 fn deserialize(&self, deserializer: &mut D) -> Result<ModuleInfo, D::Error> {
301 let archived = RkyvDeserialize::<ArchivableModuleInfo, D>::deserialize(self, deserializer)?;
302 Ok(ModuleInfo::from(archived))
303 }
304}
305
306impl PartialEq for ModuleInfo {
308 fn eq(&self, other: &Self) -> bool {
309 self.name == other.name
310 && self.imports == other.imports
311 && self.exports == other.exports
312 && self.start_function == other.start_function
313 && self.table_initializers == other.table_initializers
314 && self.passive_elements == other.passive_elements
315 && self.passive_data == other.passive_data
316 && self.global_initializers == other.global_initializers
317 && self.function_names == other.function_names
318 && self.signatures == other.signatures
319 && self.functions == other.functions
320 && self.tables == other.tables
321 && self.memories == other.memories
322 && self.globals == other.globals
323 && self.custom_sections == other.custom_sections
324 && self.custom_sections_data == other.custom_sections_data
325 && self.num_imported_functions == other.num_imported_functions
326 && self.num_imported_tables == other.num_imported_tables
327 && self.num_imported_memories == other.num_imported_memories
328 && self.num_imported_globals == other.num_imported_globals
329 }
330}
331
332impl Eq for ModuleInfo {}
333
334impl ModuleInfo {
335 pub fn new() -> Self {
337 Default::default()
338 }
339
340 pub fn hash(&self) -> Option<ModuleHash> {
342 self.hash
343 }
344
345 pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
347 self.passive_elements.get(&index).map(|es| &**es)
348 }
349
350 pub fn exported_signatures(&self) -> Vec<FunctionType> {
352 self.exports
353 .iter()
354 .filter_map(|(_name, export_index)| match export_index {
355 ExportIndex::Function(i) => {
356 let signature = self.functions.get(*i).unwrap();
357 let func_type = self.signatures.get(*signature).unwrap();
358 Some(func_type.clone())
359 }
360 _ => None,
361 })
362 .collect::<Vec<FunctionType>>()
363 }
364
365 pub fn exports(&'_ self) -> ExportsIterator<impl Iterator<Item = ExportType> + '_> {
367 let iter = self.exports.iter().map(move |(name, export_index)| {
368 let extern_type = match export_index {
369 ExportIndex::Function(i) => {
370 let signature = self.functions.get(*i).unwrap();
371 let func_type = self.signatures.get(*signature).unwrap();
372 ExternType::Function(func_type.clone())
373 }
374 ExportIndex::Table(i) => {
375 let table_type = self.tables.get(*i).unwrap();
376 ExternType::Table(*table_type)
377 }
378 ExportIndex::Memory(i) => {
379 let memory_type = self.memories.get(*i).unwrap();
380 ExternType::Memory(*memory_type)
381 }
382 ExportIndex::Global(i) => {
383 let global_type = self.globals.get(*i).unwrap();
384 ExternType::Global(*global_type)
385 }
386 };
387 ExportType::new(name, extern_type)
388 });
389 ExportsIterator::new(iter, self.exports.len())
390 }
391
392 pub fn imports(&'_ self) -> ImportsIterator<impl Iterator<Item = ImportType> + '_> {
394 let iter =
395 self.imports
396 .iter()
397 .map(move |(ImportKey { module, field, .. }, import_index)| {
398 let extern_type = match import_index {
399 ImportIndex::Function(i) => {
400 let signature = self.functions.get(*i).unwrap();
401 let func_type = self.signatures.get(*signature).unwrap();
402 ExternType::Function(func_type.clone())
403 }
404 ImportIndex::Table(i) => {
405 let table_type = self.tables.get(*i).unwrap();
406 ExternType::Table(*table_type)
407 }
408 ImportIndex::Memory(i) => {
409 let memory_type = self.memories.get(*i).unwrap();
410 ExternType::Memory(*memory_type)
411 }
412 ImportIndex::Global(i) => {
413 let global_type = self.globals.get(*i).unwrap();
414 ExternType::Global(*global_type)
415 }
416 };
417 ImportType::new(module, field, extern_type)
418 });
419 ImportsIterator::new(iter, self.imports.len())
420 }
421
422 pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Box<[u8]>> + 'a {
424 self.custom_sections
425 .iter()
426 .filter_map(move |(section_name, section_index)| {
427 if name != section_name {
428 return None;
429 }
430 Some(self.custom_sections_data[*section_index].clone())
431 })
432 }
433
434 pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
436 FunctionIndex::new(self.num_imported_functions + local_func.index())
437 }
438
439 pub fn local_func_index(&self, func: FunctionIndex) -> Option<LocalFunctionIndex> {
442 func.index()
443 .checked_sub(self.num_imported_functions)
444 .map(LocalFunctionIndex::new)
445 }
446
447 pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
449 index.index() < self.num_imported_functions
450 }
451
452 pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
454 TableIndex::new(self.num_imported_tables + local_table.index())
455 }
456
457 pub fn local_table_index(&self, table: TableIndex) -> Option<LocalTableIndex> {
460 table
461 .index()
462 .checked_sub(self.num_imported_tables)
463 .map(LocalTableIndex::new)
464 }
465
466 pub fn is_imported_table(&self, index: TableIndex) -> bool {
468 index.index() < self.num_imported_tables
469 }
470
471 pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
473 MemoryIndex::new(self.num_imported_memories + local_memory.index())
474 }
475
476 pub fn local_memory_index(&self, memory: MemoryIndex) -> Option<LocalMemoryIndex> {
479 memory
480 .index()
481 .checked_sub(self.num_imported_memories)
482 .map(LocalMemoryIndex::new)
483 }
484
485 pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
487 index.index() < self.num_imported_memories
488 }
489
490 pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
492 GlobalIndex::new(self.num_imported_globals + local_global.index())
493 }
494
495 pub fn local_global_index(&self, global: GlobalIndex) -> Option<LocalGlobalIndex> {
498 global
499 .index()
500 .checked_sub(self.num_imported_globals)
501 .map(LocalGlobalIndex::new)
502 }
503
504 pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
506 index.index() < self.num_imported_globals
507 }
508
509 pub fn name(&self) -> String {
511 match self.name {
512 Some(ref name) => name.to_string(),
513 None => "<module>".to_string(),
514 }
515 }
516
517 pub fn imported_function_types(&'_ self) -> impl Iterator<Item = FunctionType> + '_ {
519 self.functions
520 .values()
521 .take(self.num_imported_functions)
522 .map(move |sig_index| self.signatures[*sig_index].clone())
523 }
524}
525
526impl fmt::Display for ModuleInfo {
527 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
528 write!(f, "{}", self.name())
529 }
530}
531
532pub struct ExportsIterator<I: Iterator<Item = ExportType> + Sized> {
538 iter: I,
539 size: usize,
540}
541
542impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
543 pub fn new(iter: I, size: usize) -> Self {
545 Self { iter, size }
546 }
547}
548
549impl<I: Iterator<Item = ExportType> + Sized> ExactSizeIterator for ExportsIterator<I> {
550 fn len(&self) -> usize {
552 self.size
553 }
554}
555
556impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
557 pub fn functions(self) -> impl Iterator<Item = ExportType<FunctionType>> + Sized {
559 self.iter.filter_map(|extern_| match extern_.ty() {
560 ExternType::Function(ty) => Some(ExportType::new(extern_.name(), ty.clone())),
561 _ => None,
562 })
563 }
564 pub fn memories(self) -> impl Iterator<Item = ExportType<MemoryType>> + Sized {
566 self.iter.filter_map(|extern_| match extern_.ty() {
567 ExternType::Memory(ty) => Some(ExportType::new(extern_.name(), *ty)),
568 _ => None,
569 })
570 }
571 pub fn tables(self) -> impl Iterator<Item = ExportType<TableType>> + Sized {
573 self.iter.filter_map(|extern_| match extern_.ty() {
574 ExternType::Table(ty) => Some(ExportType::new(extern_.name(), *ty)),
575 _ => None,
576 })
577 }
578 pub fn globals(self) -> impl Iterator<Item = ExportType<GlobalType>> + Sized {
580 self.iter.filter_map(|extern_| match extern_.ty() {
581 ExternType::Global(ty) => Some(ExportType::new(extern_.name(), *ty)),
582 _ => None,
583 })
584 }
585}
586
587impl<I: Iterator<Item = ExportType> + Sized> Iterator for ExportsIterator<I> {
588 type Item = ExportType;
589 fn next(&mut self) -> Option<Self::Item> {
590 self.iter.next()
591 }
592}
593
594pub struct ImportsIterator<I: Iterator<Item = ImportType> + Sized> {
597 iter: I,
598 size: usize,
599}
600
601impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
602 pub fn new(iter: I, size: usize) -> Self {
604 Self { iter, size }
605 }
606}
607
608impl<I: Iterator<Item = ImportType> + Sized> ExactSizeIterator for ImportsIterator<I> {
609 fn len(&self) -> usize {
611 self.size
612 }
613}
614
615impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
616 pub fn functions(self) -> impl Iterator<Item = ImportType<FunctionType>> + Sized {
618 self.iter.filter_map(|extern_| match extern_.ty() {
619 ExternType::Function(ty) => Some(ImportType::new(
620 extern_.module(),
621 extern_.name(),
622 ty.clone(),
623 )),
624 _ => None,
625 })
626 }
627 pub fn memories(self) -> impl Iterator<Item = ImportType<MemoryType>> + Sized {
629 self.iter.filter_map(|extern_| match extern_.ty() {
630 ExternType::Memory(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
631 _ => None,
632 })
633 }
634 pub fn tables(self) -> impl Iterator<Item = ImportType<TableType>> + Sized {
636 self.iter.filter_map(|extern_| match extern_.ty() {
637 ExternType::Table(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
638 _ => None,
639 })
640 }
641 pub fn globals(self) -> impl Iterator<Item = ImportType<GlobalType>> + Sized {
643 self.iter.filter_map(|extern_| match extern_.ty() {
644 ExternType::Global(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
645 _ => None,
646 })
647 }
648}
649
650impl<I: Iterator<Item = ImportType> + Sized> Iterator for ImportsIterator<I> {
651 type Item = ImportType;
652 fn next(&mut self) -> Option<Self::Item> {
653 self.iter.next()
654 }
655}