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, LocalTagIndex, MemoryIndex, MemoryType,
12 ModuleHash, SignatureIndex, TableIndex, TableInitializer, TableType, TagIndex, TagType,
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 tags: PrimaryMap<TagIndex, SignatureIndex>,
170
171 pub custom_sections: IndexMap<String, CustomSectionIndex>,
173
174 pub custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
176
177 pub num_imported_functions: usize,
179
180 pub num_imported_tables: usize,
182
183 pub num_imported_memories: usize,
185
186 pub num_imported_tags: usize,
188
189 pub num_imported_globals: usize,
191}
192
193#[derive(Debug, RkyvSerialize, RkyvDeserialize, Archive)]
195#[rkyv(derive(Debug))]
196pub struct ArchivableModuleInfo {
197 name: Option<String>,
198 hash: Option<ModuleHash>,
199 imports: IndexMap<ImportKey, ImportIndex>,
200 exports: IndexMap<String, ExportIndex>,
201 start_function: Option<FunctionIndex>,
202 table_initializers: Vec<TableInitializer>,
203 passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
204 passive_data: BTreeMap<DataIndex, Box<[u8]>>,
205 global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
206 function_names: BTreeMap<FunctionIndex, String>,
207 signatures: PrimaryMap<SignatureIndex, FunctionType>,
208 functions: PrimaryMap<FunctionIndex, SignatureIndex>,
209 tables: PrimaryMap<TableIndex, TableType>,
210 memories: PrimaryMap<MemoryIndex, MemoryType>,
211 globals: PrimaryMap<GlobalIndex, GlobalType>,
212 tags: PrimaryMap<TagIndex, SignatureIndex>,
213 custom_sections: IndexMap<String, CustomSectionIndex>,
214 custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
215 num_imported_functions: usize,
216 num_imported_tables: usize,
217 num_imported_tags: usize,
218 num_imported_memories: usize,
219 num_imported_globals: usize,
220}
221
222impl From<ModuleInfo> for ArchivableModuleInfo {
223 fn from(it: ModuleInfo) -> Self {
224 Self {
225 name: it.name,
226 hash: it.hash,
227 imports: it.imports,
228 exports: it.exports,
229 start_function: it.start_function,
230 table_initializers: it.table_initializers,
231 passive_elements: it.passive_elements.into_iter().collect(),
232 passive_data: it.passive_data.into_iter().collect(),
233 global_initializers: it.global_initializers,
234 function_names: it.function_names.into_iter().collect(),
235 signatures: it.signatures,
236 functions: it.functions,
237 tables: it.tables,
238 memories: it.memories,
239 globals: it.globals,
240 tags: it.tags,
241 custom_sections: it.custom_sections,
242 custom_sections_data: it.custom_sections_data,
243 num_imported_functions: it.num_imported_functions,
244 num_imported_tables: it.num_imported_tables,
245 num_imported_tags: it.num_imported_tags,
246 num_imported_memories: it.num_imported_memories,
247 num_imported_globals: it.num_imported_globals,
248 }
249 }
250}
251
252impl From<ArchivableModuleInfo> for ModuleInfo {
253 fn from(it: ArchivableModuleInfo) -> Self {
254 Self {
255 id: Default::default(),
256 name: it.name,
257 hash: it.hash,
258 imports: it.imports,
259 exports: it.exports,
260 start_function: it.start_function,
261 table_initializers: it.table_initializers,
262 passive_elements: it.passive_elements.into_iter().collect(),
263 passive_data: it.passive_data.into_iter().collect(),
264 global_initializers: it.global_initializers,
265 function_names: it.function_names.into_iter().collect(),
266 signatures: it.signatures,
267 functions: it.functions,
268 tables: it.tables,
269 memories: it.memories,
270 globals: it.globals,
271 tags: it.tags,
272 custom_sections: it.custom_sections,
273 custom_sections_data: it.custom_sections_data,
274 num_imported_functions: it.num_imported_functions,
275 num_imported_tables: it.num_imported_tables,
276 num_imported_tags: it.num_imported_tags,
277 num_imported_memories: it.num_imported_memories,
278 num_imported_globals: it.num_imported_globals,
279 }
280 }
281}
282
283impl From<&ModuleInfo> for ArchivableModuleInfo {
284 fn from(it: &ModuleInfo) -> Self {
285 Self::from(it.clone())
286 }
287}
288
289impl Archive for ModuleInfo {
290 type Archived = <ArchivableModuleInfo as Archive>::Archived;
291 type Resolver = <ArchivableModuleInfo as Archive>::Resolver;
292
293 fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
294 ArchivableModuleInfo::from(self).resolve(resolver, out)
295 }
296}
297
298impl<S: rkyv::ser::Allocator + rkyv::ser::Writer + Fallible + ?Sized> RkyvSerialize<S>
299 for ModuleInfo
300where
301 <S as Fallible>::Error: rkyv::rancor::Source + rkyv::rancor::Trace,
302{
303 fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
304 ArchivableModuleInfo::from(self).serialize(serializer)
305 }
306}
307
308impl<D: Fallible + ?Sized> RkyvDeserialize<ModuleInfo, D> for ArchivedArchivableModuleInfo
309where
310 D::Error: Source + Trace,
311{
312 fn deserialize(&self, deserializer: &mut D) -> Result<ModuleInfo, D::Error> {
313 let archived = RkyvDeserialize::<ArchivableModuleInfo, D>::deserialize(self, deserializer)?;
314 Ok(ModuleInfo::from(archived))
315 }
316}
317
318impl PartialEq for ModuleInfo {
320 fn eq(&self, other: &Self) -> bool {
321 self.name == other.name
322 && self.imports == other.imports
323 && self.exports == other.exports
324 && self.start_function == other.start_function
325 && self.table_initializers == other.table_initializers
326 && self.passive_elements == other.passive_elements
327 && self.passive_data == other.passive_data
328 && self.global_initializers == other.global_initializers
329 && self.function_names == other.function_names
330 && self.signatures == other.signatures
331 && self.functions == other.functions
332 && self.tables == other.tables
333 && self.memories == other.memories
334 && self.globals == other.globals
335 && self.tags == other.tags
336 && self.custom_sections == other.custom_sections
337 && self.custom_sections_data == other.custom_sections_data
338 && self.num_imported_functions == other.num_imported_functions
339 && self.num_imported_tables == other.num_imported_tables
340 && self.num_imported_tags == other.num_imported_tags
341 && self.num_imported_memories == other.num_imported_memories
342 && self.num_imported_globals == other.num_imported_globals
343 }
344}
345
346impl Eq for ModuleInfo {}
347
348impl ModuleInfo {
349 pub fn new() -> Self {
351 Default::default()
352 }
353
354 pub fn hash(&self) -> Option<ModuleHash> {
356 self.hash
357 }
358
359 pub fn hash_string(&self) -> Option<String> {
361 self.hash.map(|m| m.to_string())
362 }
363
364 pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
366 self.passive_elements.get(&index).map(|es| &**es)
367 }
368
369 pub fn exported_signatures(&self) -> Vec<FunctionType> {
371 self.exports
372 .iter()
373 .filter_map(|(_name, export_index)| match export_index {
374 ExportIndex::Function(i) => {
375 let signature = self.functions.get(*i).unwrap();
376 let func_type = self.signatures.get(*signature).unwrap();
377 Some(func_type.clone())
378 }
379 _ => None,
380 })
381 .collect::<Vec<FunctionType>>()
382 }
383
384 pub fn exports(&'_ self) -> ExportsIterator<Box<dyn Iterator<Item = ExportType> + '_>> {
386 let iter = self.exports.iter().map(move |(name, export_index)| {
387 let extern_type = match export_index {
388 ExportIndex::Function(i) => {
389 let signature = self.functions.get(*i).unwrap();
390 let func_type = self.signatures.get(*signature).unwrap();
391 ExternType::Function(func_type.clone())
392 }
393 ExportIndex::Table(i) => {
394 let table_type = self.tables.get(*i).unwrap();
395 ExternType::Table(*table_type)
396 }
397 ExportIndex::Memory(i) => {
398 let memory_type = self.memories.get(*i).unwrap();
399 ExternType::Memory(*memory_type)
400 }
401 ExportIndex::Global(i) => {
402 let global_type = self.globals.get(*i).unwrap();
403 ExternType::Global(*global_type)
404 }
405 ExportIndex::Tag(i) => {
406 let signature = self.tags.get(*i).unwrap();
407 let tag_type = self.signatures.get(*signature).unwrap();
408
409 ExternType::Tag(TagType {
410 kind: crate::types::TagKind::Exception,
411 params: tag_type.params().into(),
412 })
413 }
414 };
415 ExportType::new(name, extern_type)
416 });
417 ExportsIterator::new(Box::new(iter), self.exports.len())
418 }
419
420 pub fn imports(&'_ self) -> ImportsIterator<Box<dyn Iterator<Item = ImportType> + '_>> {
422 let iter =
423 self.imports
424 .iter()
425 .map(move |(ImportKey { module, field, .. }, import_index)| {
426 let extern_type = match import_index {
427 ImportIndex::Function(i) => {
428 let signature = self.functions.get(*i).unwrap();
429 let func_type = self.signatures.get(*signature).unwrap();
430 ExternType::Function(func_type.clone())
431 }
432 ImportIndex::Table(i) => {
433 let table_type = self.tables.get(*i).unwrap();
434 ExternType::Table(*table_type)
435 }
436 ImportIndex::Memory(i) => {
437 let memory_type = self.memories.get(*i).unwrap();
438 ExternType::Memory(*memory_type)
439 }
440 ImportIndex::Global(i) => {
441 let global_type = self.globals.get(*i).unwrap();
442 ExternType::Global(*global_type)
443 }
444 ImportIndex::Tag(i) => {
445 let tag_type = self.tags.get(*i).unwrap();
446 let func_type = self.signatures.get(*tag_type).unwrap();
447 ExternType::Tag(TagType::from_fn_type(
448 crate::TagKind::Exception,
449 func_type.clone(),
450 ))
451 }
452 };
453 ImportType::new(module, field, extern_type)
454 });
455 ImportsIterator::new(Box::new(iter), self.imports.len())
456 }
457
458 pub fn custom_sections<'a>(
460 &'a self,
461 name: &'a str,
462 ) -> Box<impl Iterator<Item = Box<[u8]>> + 'a> {
463 Box::new(
464 self.custom_sections
465 .iter()
466 .filter_map(move |(section_name, section_index)| {
467 if name != section_name {
468 return None;
469 }
470 Some(self.custom_sections_data[*section_index].clone())
471 }),
472 )
473 }
474
475 pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
477 FunctionIndex::new(self.num_imported_functions + local_func.index())
478 }
479
480 pub fn local_func_index(&self, func: FunctionIndex) -> Option<LocalFunctionIndex> {
483 func.index()
484 .checked_sub(self.num_imported_functions)
485 .map(LocalFunctionIndex::new)
486 }
487
488 pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
490 index.index() < self.num_imported_functions
491 }
492
493 pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
495 TableIndex::new(self.num_imported_tables + local_table.index())
496 }
497
498 pub fn local_table_index(&self, table: TableIndex) -> Option<LocalTableIndex> {
501 table
502 .index()
503 .checked_sub(self.num_imported_tables)
504 .map(LocalTableIndex::new)
505 }
506
507 pub fn is_imported_table(&self, index: TableIndex) -> bool {
509 index.index() < self.num_imported_tables
510 }
511
512 pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
514 MemoryIndex::new(self.num_imported_memories + local_memory.index())
515 }
516
517 pub fn local_memory_index(&self, memory: MemoryIndex) -> Option<LocalMemoryIndex> {
520 memory
521 .index()
522 .checked_sub(self.num_imported_memories)
523 .map(LocalMemoryIndex::new)
524 }
525
526 pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
528 index.index() < self.num_imported_memories
529 }
530
531 pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
533 GlobalIndex::new(self.num_imported_globals + local_global.index())
534 }
535
536 pub fn local_global_index(&self, global: GlobalIndex) -> Option<LocalGlobalIndex> {
539 global
540 .index()
541 .checked_sub(self.num_imported_globals)
542 .map(LocalGlobalIndex::new)
543 }
544
545 pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
547 index.index() < self.num_imported_globals
548 }
549
550 pub fn global_type(&self, global_index: GlobalIndex) -> Option<GlobalType> {
552 self.globals.get(global_index).copied()
553 }
554
555 pub fn tag_index(&self, local_tag: LocalTagIndex) -> TagIndex {
557 TagIndex::new(self.num_imported_tags + local_tag.index())
558 }
559
560 pub fn local_tag_index(&self, tag: TagIndex) -> Option<LocalTagIndex> {
563 tag.index()
564 .checked_sub(self.num_imported_tags)
565 .map(LocalTagIndex::new)
566 }
567
568 pub fn is_imported_tag(&self, index: TagIndex) -> bool {
570 index.index() < self.num_imported_tags
571 }
572
573 pub fn name(&self) -> String {
575 match self.name {
576 Some(ref name) => name.to_string(),
577 None => "<module>".to_string(),
578 }
579 }
580
581 pub fn imported_function_types(&'_ self) -> impl Iterator<Item = FunctionType> + '_ {
583 self.functions
584 .values()
585 .take(self.num_imported_functions)
586 .map(move |sig_index| self.signatures[*sig_index].clone())
587 }
588
589 pub fn get_function_name(&self, func_index: FunctionIndex) -> String {
591 self.function_names
592 .get(&func_index)
593 .cloned()
594 .unwrap_or_else(|| format!("function_{}", func_index.as_u32()))
595 }
596}
597
598impl fmt::Display for ModuleInfo {
599 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
600 write!(f, "{}", self.name())
601 }
602}
603
604pub struct ExportsIterator<I: Iterator<Item = ExportType> + Sized> {
610 iter: I,
611 size: usize,
612}
613
614impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
615 pub fn new(iter: I, size: usize) -> Self {
617 Self { iter, size }
618 }
619}
620
621impl<I: Iterator<Item = ExportType> + Sized> ExactSizeIterator for ExportsIterator<I> {
622 fn len(&self) -> usize {
624 self.size
625 }
626}
627
628impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
629 pub fn functions(self) -> impl Iterator<Item = ExportType<FunctionType>> + Sized {
631 self.iter.filter_map(|extern_| match extern_.ty() {
632 ExternType::Function(ty) => Some(ExportType::new(extern_.name(), ty.clone())),
633 _ => None,
634 })
635 }
636 pub fn memories(self) -> impl Iterator<Item = ExportType<MemoryType>> + Sized {
638 self.iter.filter_map(|extern_| match extern_.ty() {
639 ExternType::Memory(ty) => Some(ExportType::new(extern_.name(), *ty)),
640 _ => None,
641 })
642 }
643 pub fn tables(self) -> impl Iterator<Item = ExportType<TableType>> + Sized {
645 self.iter.filter_map(|extern_| match extern_.ty() {
646 ExternType::Table(ty) => Some(ExportType::new(extern_.name(), *ty)),
647 _ => None,
648 })
649 }
650 pub fn globals(self) -> impl Iterator<Item = ExportType<GlobalType>> + Sized {
652 self.iter.filter_map(|extern_| match extern_.ty() {
653 ExternType::Global(ty) => Some(ExportType::new(extern_.name(), *ty)),
654 _ => None,
655 })
656 }
657 pub fn tags(self) -> impl Iterator<Item = ExportType<TagType>> + Sized {
659 self.iter.filter_map(|extern_| match extern_.ty() {
660 ExternType::Tag(ty) => Some(ExportType::new(extern_.name(), ty.clone())),
661 _ => None,
662 })
663 }
664}
665
666impl<I: Iterator<Item = ExportType> + Sized> Iterator for ExportsIterator<I> {
667 type Item = ExportType;
668 fn next(&mut self) -> Option<Self::Item> {
669 self.iter.next()
670 }
671}
672
673pub struct ImportsIterator<I: Iterator<Item = ImportType> + Sized> {
676 iter: I,
677 size: usize,
678}
679
680impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
681 pub fn new(iter: I, size: usize) -> Self {
683 Self { iter, size }
684 }
685}
686
687impl<I: Iterator<Item = ImportType> + Sized> ExactSizeIterator for ImportsIterator<I> {
688 fn len(&self) -> usize {
690 self.size
691 }
692}
693
694impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
695 pub fn functions(self) -> impl Iterator<Item = ImportType<FunctionType>> + Sized {
697 self.iter.filter_map(|extern_| match extern_.ty() {
698 ExternType::Function(ty) => Some(ImportType::new(
699 extern_.module(),
700 extern_.name(),
701 ty.clone(),
702 )),
703 _ => None,
704 })
705 }
706 pub fn memories(self) -> impl Iterator<Item = ImportType<MemoryType>> + Sized {
708 self.iter.filter_map(|extern_| match extern_.ty() {
709 ExternType::Memory(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
710 _ => None,
711 })
712 }
713 pub fn tables(self) -> impl Iterator<Item = ImportType<TableType>> + Sized {
715 self.iter.filter_map(|extern_| match extern_.ty() {
716 ExternType::Table(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
717 _ => None,
718 })
719 }
720 pub fn globals(self) -> impl Iterator<Item = ImportType<GlobalType>> + Sized {
722 self.iter.filter_map(|extern_| match extern_.ty() {
723 ExternType::Global(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
724 _ => None,
725 })
726 }
727 pub fn tags(self) -> impl Iterator<Item = ImportType<TagType>> + Sized {
729 self.iter.filter_map(|extern_| match extern_.ty() {
730 ExternType::Tag(ty) => Some(ImportType::new(
731 extern_.module(),
732 extern_.name(),
733 ty.clone(),
734 )),
735 _ => None,
736 })
737 }
738}
739
740impl<I: Iterator<Item = ImportType> + Sized> Iterator for ImportsIterator<I> {
741 type Item = ImportType;
742 fn next(&mut self) -> Option<Self::Item> {
743 self.iter.next()
744 }
745}