wasmer_types/
module.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/main/docs/ATTRIBUTIONS.md
3
4//! Data structure for representing WebAssembly modules in a
5//! `wasmer::Module`.
6
7use crate::entity::{EntityRef, PrimaryMap};
8use crate::indexes::SignatureHash;
9use crate::{
10    CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, ExportType, ExternType, FunctionIndex,
11    FunctionType, GlobalIndex, GlobalInit, GlobalType, ImportIndex, ImportType, LocalFunctionIndex,
12    LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, LocalTagIndex, MemoryIndex, MemoryType,
13    ModuleHash, SignatureIndex, TableIndex, TableInitializer, TableType, TagIndex, TagType,
14    WasmError, WasmResult,
15};
16
17use indexmap::IndexMap;
18use itertools::Itertools;
19use rkyv::rancor::{Fallible, Source, Trace};
20use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
21#[cfg(feature = "enable-serde")]
22use serde::{Deserialize, Serialize};
23use std::collections::BTreeMap;
24use std::collections::HashMap;
25use std::fmt;
26use std::iter::ExactSizeIterator;
27use std::sync::Arc;
28use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
29
30#[derive(Debug, Clone, RkyvSerialize, RkyvDeserialize, Archive)]
31#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
32#[rkyv(derive(Debug))]
33pub struct ModuleId {
34    id: usize,
35}
36
37impl ModuleId {
38    pub fn id(&self) -> String {
39        format!("{}", self.id)
40    }
41}
42
43impl Default for ModuleId {
44    fn default() -> Self {
45        static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
46        Self {
47            id: NEXT_ID.fetch_add(1, SeqCst),
48        }
49    }
50}
51
52/// Hash key of an import
53#[derive(Debug, Hash, Eq, PartialEq, Clone, Default, RkyvSerialize, RkyvDeserialize, Archive)]
54#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
55#[rkyv(derive(PartialOrd, Ord, PartialEq, Eq, Hash, Debug))]
56pub struct ImportKey {
57    /// Module name
58    pub module: String,
59    /// Field name
60    pub field: String,
61    /// Import index
62    pub import_idx: u32,
63}
64
65impl From<(String, String, u32)> for ImportKey {
66    fn from((module, field, import_idx): (String, String, u32)) -> Self {
67        Self {
68            module,
69            field,
70            import_idx,
71        }
72    }
73}
74
75#[cfg(feature = "enable-serde")]
76mod serde_imports {
77
78    use crate::ImportIndex;
79    use crate::ImportKey;
80    use indexmap::IndexMap;
81    use serde::{Deserialize, Deserializer, Serialize, Serializer};
82
83    type InitialType = IndexMap<ImportKey, ImportIndex>;
84    type SerializedType = Vec<(ImportKey, ImportIndex)>;
85    // IndexMap<ImportKey, ImportIndex>
86    // Vec<
87    pub fn serialize<S: Serializer>(s: &InitialType, serializer: S) -> Result<S::Ok, S::Error> {
88        let vec: SerializedType = s
89            .iter()
90            .map(|(a, b)| (a.clone(), b.clone()))
91            .collect::<Vec<_>>();
92        vec.serialize(serializer)
93    }
94
95    pub fn deserialize<'de, D: Deserializer<'de>>(
96        deserializer: D,
97    ) -> Result<InitialType, D::Error> {
98        let serialized = <SerializedType as Deserialize>::deserialize(deserializer)?;
99        Ok(serialized.into_iter().collect())
100    }
101}
102
103/// A translated WebAssembly module, excluding the function bodies and
104/// memory initializers.
105///
106/// IMPORTANT: since this struct will be serialized as part of the compiled module artifact,
107/// if you change this struct, do not forget to update [`MetadataHeader::version`](crate::serialize::MetadataHeader)
108/// to make sure we don't break compatibility between versions.
109#[derive(Debug, Clone, Default)]
110#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
111#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
112pub struct ModuleInfo {
113    /// A unique identifier (within this process) for this module.
114    ///
115    /// We skip serialization/deserialization of this field, as it
116    /// should be computed by the process.
117    /// It's not skipped in rkyv, but that is okay, because even though it's skipped in bincode/serde
118    /// it's still deserialized back as a garbage number, and later override from computed by the process
119    #[cfg_attr(feature = "enable-serde", serde(skip_serializing, skip_deserializing))]
120    pub id: ModuleId,
121
122    /// hash of the module
123    pub hash: Option<ModuleHash>,
124
125    /// The name of this wasm module, often found in the wasm file.
126    pub name: Option<String>,
127
128    /// Imported entities with the (module, field, index_of_the_import)
129    ///
130    /// Keeping the `index_of_the_import` is important, as there can be
131    /// two same references to the same import, and we don't want to confuse
132    /// them.
133    #[cfg_attr(feature = "enable-serde", serde(with = "serde_imports"))]
134    pub imports: IndexMap<ImportKey, ImportIndex>,
135
136    /// Exported entities.
137    pub exports: IndexMap<String, ExportIndex>,
138
139    /// The module "start" function, if present.
140    pub start_function: Option<FunctionIndex>,
141
142    /// WebAssembly table initializers.
143    pub table_initializers: Vec<TableInitializer>,
144
145    /// WebAssembly passive elements.
146    pub passive_elements: HashMap<ElemIndex, Box<[FunctionIndex]>>,
147
148    /// WebAssembly passive data segments.
149    ///
150    /// Stored as `Arc<[u8]>` so that every instance created from this module can
151    /// share the same immutable segment bytes (a cheap refcount bump) instead of
152    /// deep-copying them. `memory.init` only ever reads these bytes, and
153    /// `data.drop` is tracked per-instance, so there is no reason to clone them
154    /// per instance.
155    pub passive_data: HashMap<DataIndex, Arc<[u8]>>,
156
157    /// WebAssembly global initializers.
158    pub global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
159
160    /// WebAssembly function names.
161    pub function_names: HashMap<FunctionIndex, String>,
162
163    /// WebAssembly function signatures.
164    pub signatures: PrimaryMap<SignatureIndex, FunctionType>,
165
166    /// WebAssembly function signature hashes.
167    pub signature_hashes: PrimaryMap<SignatureIndex, SignatureHash>,
168
169    /// WebAssembly functions (imported and local).
170    pub functions: PrimaryMap<FunctionIndex, SignatureIndex>,
171
172    /// WebAssembly tables (imported and local).
173    pub tables: PrimaryMap<TableIndex, TableType>,
174
175    /// WebAssembly linear memories (imported and local).
176    pub memories: PrimaryMap<MemoryIndex, MemoryType>,
177
178    /// WebAssembly global variables (imported and local).
179    pub globals: PrimaryMap<GlobalIndex, GlobalType>,
180
181    /// WebAssembly tag variables (imported and local).
182    pub tags: PrimaryMap<TagIndex, SignatureIndex>,
183
184    /// Custom sections in the module.
185    pub custom_sections: IndexMap<String, CustomSectionIndex>,
186
187    /// The data for each CustomSection in the module.
188    pub custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
189
190    /// Number of imported functions in the module.
191    pub num_imported_functions: usize,
192
193    /// Number of imported tables in the module.
194    pub num_imported_tables: usize,
195
196    /// Number of imported memories in the module.
197    pub num_imported_memories: usize,
198
199    /// Number of imported tags in the module.
200    pub num_imported_tags: usize,
201
202    /// Number of imported globals in the module.
203    pub num_imported_globals: usize,
204}
205
206// Tripwire for `ModuleInfo::passive_data` above: the runtime form is `Arc<[u8]>`
207// (shared across instances), but the archived form `ArchivableModuleInfo::passive_data`
208// is still `Box<[u8]>`, so the two `From` impls copy the bytes on every module
209// serialize/deserialize. Switching the archived form to `Arc<[u8]>` (rkyv supports
210// it) drops those copies but changes the artifact layout. Do it the next time the
211// artifact format version is bumped anyway.
212const _: () = assert!(
213    crate::MetadataHeader::CURRENT_VERSION == 21,
214    "Artifact version bumped: change `ArchivableModuleInfo::passive_data` from \
215     `Box<[u8]>` to `Arc<[u8]>` (and drop the copies in the `From` impls)",
216);
217
218/// Mirror version of ModuleInfo that can derive rkyv traits
219#[derive(Debug, RkyvSerialize, RkyvDeserialize, Archive)]
220#[rkyv(derive(Debug))]
221pub struct ArchivableModuleInfo {
222    name: Option<String>,
223    hash: Option<ModuleHash>,
224    imports: IndexMap<ImportKey, ImportIndex>,
225    exports: IndexMap<String, ExportIndex>,
226    start_function: Option<FunctionIndex>,
227    table_initializers: Vec<TableInitializer>,
228    passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
229    passive_data: BTreeMap<DataIndex, Box<[u8]>>,
230    global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
231    function_names: BTreeMap<FunctionIndex, String>,
232    signatures: PrimaryMap<SignatureIndex, FunctionType>,
233    signature_hashes: PrimaryMap<SignatureIndex, SignatureHash>,
234    functions: PrimaryMap<FunctionIndex, SignatureIndex>,
235    tables: PrimaryMap<TableIndex, TableType>,
236    memories: PrimaryMap<MemoryIndex, MemoryType>,
237    globals: PrimaryMap<GlobalIndex, GlobalType>,
238    tags: PrimaryMap<TagIndex, SignatureIndex>,
239    custom_sections: IndexMap<String, CustomSectionIndex>,
240    custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
241    num_imported_functions: usize,
242    num_imported_tables: usize,
243    num_imported_tags: usize,
244    num_imported_memories: usize,
245    num_imported_globals: usize,
246}
247
248impl From<ModuleInfo> for ArchivableModuleInfo {
249    fn from(it: ModuleInfo) -> Self {
250        Self {
251            name: it.name,
252            hash: it.hash,
253            imports: it.imports,
254            exports: it.exports,
255            start_function: it.start_function,
256            table_initializers: it.table_initializers,
257            passive_elements: it.passive_elements.into_iter().collect(),
258            // `ArchivableModuleInfo` owns its bytes (`Box<[u8]>`); copy them out
259            // of the shared `Arc` for the on-disk representation.
260            passive_data: it
261                .passive_data
262                .into_iter()
263                .map(|(idx, bytes)| (idx, Box::from(&*bytes)))
264                .collect(),
265            global_initializers: it.global_initializers,
266            function_names: it.function_names.into_iter().collect(),
267            signatures: it.signatures,
268            signature_hashes: it.signature_hashes,
269            functions: it.functions,
270            tables: it.tables,
271            memories: it.memories,
272            globals: it.globals,
273            tags: it.tags,
274            custom_sections: it.custom_sections,
275            custom_sections_data: it.custom_sections_data,
276            num_imported_functions: it.num_imported_functions,
277            num_imported_tables: it.num_imported_tables,
278            num_imported_tags: it.num_imported_tags,
279            num_imported_memories: it.num_imported_memories,
280            num_imported_globals: it.num_imported_globals,
281        }
282    }
283}
284
285impl From<ArchivableModuleInfo> for ModuleInfo {
286    fn from(it: ArchivableModuleInfo) -> Self {
287        Self {
288            id: Default::default(),
289            name: it.name,
290            hash: it.hash,
291            imports: it.imports,
292            exports: it.exports,
293            start_function: it.start_function,
294            table_initializers: it.table_initializers,
295            passive_elements: it.passive_elements.into_iter().collect(),
296            passive_data: it
297                .passive_data
298                .into_iter()
299                .map(|(idx, bytes)| (idx, Arc::from(bytes)))
300                .collect(),
301            global_initializers: it.global_initializers,
302            function_names: it.function_names.into_iter().collect(),
303            signatures: it.signatures,
304            signature_hashes: it.signature_hashes,
305            functions: it.functions,
306            tables: it.tables,
307            memories: it.memories,
308            globals: it.globals,
309            tags: it.tags,
310            custom_sections: it.custom_sections,
311            custom_sections_data: it.custom_sections_data,
312            num_imported_functions: it.num_imported_functions,
313            num_imported_tables: it.num_imported_tables,
314            num_imported_tags: it.num_imported_tags,
315            num_imported_memories: it.num_imported_memories,
316            num_imported_globals: it.num_imported_globals,
317        }
318    }
319}
320
321impl From<&ModuleInfo> for ArchivableModuleInfo {
322    fn from(it: &ModuleInfo) -> Self {
323        Self::from(it.clone())
324    }
325}
326
327impl Archive for ModuleInfo {
328    type Archived = <ArchivableModuleInfo as Archive>::Archived;
329    type Resolver = <ArchivableModuleInfo as Archive>::Resolver;
330
331    fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
332        ArchivableModuleInfo::from(self).resolve(resolver, out)
333    }
334}
335
336impl<S: rkyv::ser::Allocator + rkyv::ser::Writer + Fallible + ?Sized> RkyvSerialize<S>
337    for ModuleInfo
338where
339    <S as Fallible>::Error: rkyv::rancor::Source + rkyv::rancor::Trace,
340{
341    fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
342        ArchivableModuleInfo::from(self).serialize(serializer)
343    }
344}
345
346impl<D: Fallible + ?Sized> RkyvDeserialize<ModuleInfo, D> for ArchivedArchivableModuleInfo
347where
348    D::Error: Source + Trace,
349{
350    fn deserialize(&self, deserializer: &mut D) -> Result<ModuleInfo, D::Error> {
351        let archived = RkyvDeserialize::<ArchivableModuleInfo, D>::deserialize(self, deserializer)?;
352        Ok(ModuleInfo::from(archived))
353    }
354}
355
356// For test serialization correctness, everything except module id should be same
357impl PartialEq for ModuleInfo {
358    fn eq(&self, other: &Self) -> bool {
359        self.name == other.name
360            && self.imports == other.imports
361            && self.exports == other.exports
362            && self.start_function == other.start_function
363            && self.table_initializers == other.table_initializers
364            && self.passive_elements == other.passive_elements
365            && self.passive_data == other.passive_data
366            && self.global_initializers == other.global_initializers
367            && self.function_names == other.function_names
368            && self.signatures == other.signatures
369            && self.signature_hashes == other.signature_hashes
370            && self.functions == other.functions
371            && self.tables == other.tables
372            && self.memories == other.memories
373            && self.globals == other.globals
374            && self.tags == other.tags
375            && self.custom_sections == other.custom_sections
376            && self.custom_sections_data == other.custom_sections_data
377            && self.num_imported_functions == other.num_imported_functions
378            && self.num_imported_tables == other.num_imported_tables
379            && self.num_imported_tags == other.num_imported_tags
380            && self.num_imported_memories == other.num_imported_memories
381            && self.num_imported_globals == other.num_imported_globals
382    }
383}
384
385impl Eq for ModuleInfo {}
386
387impl ModuleInfo {
388    /// Allocates the module data structures.
389    pub fn new() -> Self {
390        Default::default()
391    }
392
393    /// Returns the module hash if available
394    pub fn hash(&self) -> Option<ModuleHash> {
395        self.hash
396    }
397
398    /// Returns the module hash as String if available
399    pub fn hash_string(&self) -> Option<String> {
400        self.hash.map(|m| m.to_string())
401    }
402
403    /// Validates invariants for the precomputed signature hashes.
404    pub fn validate_signature_hashes(&self) -> WasmResult<()> {
405        // TODO: the signatures are not distinct, thus we cannot just validate signature_hashes.
406        if self
407            .signatures
408            .iter()
409            .map(|(_, signature)| signature)
410            .unique()
411            .map(|signature| signature.signature_hash())
412            .all_unique()
413        {
414            Ok(())
415        } else {
416            Err(WasmError::Generic("signature hash collision".to_string()))
417        }
418    }
419
420    /// Get the given passive element, if it exists.
421    pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
422        self.passive_elements.get(&index).map(|es| &**es)
423    }
424
425    /// Get the exported signatures of the module
426    pub fn exported_signatures(&self) -> Vec<FunctionType> {
427        self.exports
428            .iter()
429            .filter_map(|(_name, export_index)| match export_index {
430                ExportIndex::Function(i) => {
431                    let signature = self.functions.get(*i).unwrap();
432                    let func_type = self.signatures.get(*signature).unwrap();
433                    Some(func_type.clone())
434                }
435                _ => None,
436            })
437            .collect::<Vec<FunctionType>>()
438    }
439
440    /// Get the export types of the module
441    pub fn exports(&'_ self) -> ExportsIterator<Box<dyn Iterator<Item = ExportType> + '_>> {
442        let iter = self.exports.iter().map(move |(name, export_index)| {
443            let extern_type = match export_index {
444                ExportIndex::Function(i) => {
445                    let signature = self.functions.get(*i).unwrap();
446                    let func_type = self.signatures.get(*signature).unwrap();
447                    ExternType::Function(func_type.clone())
448                }
449                ExportIndex::Table(i) => {
450                    let table_type = self.tables.get(*i).unwrap();
451                    ExternType::Table(*table_type)
452                }
453                ExportIndex::Memory(i) => {
454                    let memory_type = self.memories.get(*i).unwrap();
455                    ExternType::Memory(*memory_type)
456                }
457                ExportIndex::Global(i) => {
458                    let global_type = self.globals.get(*i).unwrap();
459                    ExternType::Global(*global_type)
460                }
461                ExportIndex::Tag(i) => {
462                    let signature = self.tags.get(*i).unwrap();
463                    let tag_type = self.signatures.get(*signature).unwrap();
464
465                    ExternType::Tag(TagType {
466                        kind: crate::types::TagKind::Exception,
467                        params: tag_type.params().into(),
468                    })
469                }
470            };
471            ExportType::new(name, extern_type)
472        });
473        ExportsIterator::new(Box::new(iter), self.exports.len())
474    }
475
476    /// Get the import types of the module
477    pub fn imports(&'_ self) -> ImportsIterator<Box<dyn Iterator<Item = ImportType> + '_>> {
478        let iter =
479            self.imports
480                .iter()
481                .map(move |(ImportKey { module, field, .. }, import_index)| {
482                    let extern_type = match import_index {
483                        ImportIndex::Function(i) => {
484                            let signature = self.functions.get(*i).unwrap();
485                            let func_type = self.signatures.get(*signature).unwrap();
486                            ExternType::Function(func_type.clone())
487                        }
488                        ImportIndex::Table(i) => {
489                            let table_type = self.tables.get(*i).unwrap();
490                            ExternType::Table(*table_type)
491                        }
492                        ImportIndex::Memory(i) => {
493                            let memory_type = self.memories.get(*i).unwrap();
494                            ExternType::Memory(*memory_type)
495                        }
496                        ImportIndex::Global(i) => {
497                            let global_type = self.globals.get(*i).unwrap();
498                            ExternType::Global(*global_type)
499                        }
500                        ImportIndex::Tag(i) => {
501                            let tag_type = self.tags.get(*i).unwrap();
502                            let func_type = self.signatures.get(*tag_type).unwrap();
503                            ExternType::Tag(TagType::from_fn_type(
504                                crate::TagKind::Exception,
505                                func_type.clone(),
506                            ))
507                        }
508                    };
509                    ImportType::new(module, field, extern_type)
510                });
511        ImportsIterator::new(Box::new(iter), self.imports.len())
512    }
513
514    /// Get the custom sections of the module given a `name`.
515    pub fn custom_sections<'a>(
516        &'a self,
517        name: &'a str,
518    ) -> Box<impl Iterator<Item = Box<[u8]>> + 'a> {
519        Box::new(
520            self.custom_sections
521                .iter()
522                .filter_map(move |(section_name, section_index)| {
523                    if name != section_name {
524                        return None;
525                    }
526                    Some(self.custom_sections_data[*section_index].clone())
527                }),
528        )
529    }
530
531    /// Convert a `LocalFunctionIndex` into a `FunctionIndex`.
532    pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
533        FunctionIndex::new(self.num_imported_functions + local_func.index())
534    }
535
536    /// Convert a `FunctionIndex` into a `LocalFunctionIndex`. Returns None if the
537    /// index is an imported function.
538    pub fn local_func_index(&self, func: FunctionIndex) -> Option<LocalFunctionIndex> {
539        func.index()
540            .checked_sub(self.num_imported_functions)
541            .map(LocalFunctionIndex::new)
542    }
543
544    /// Test whether the given function index is for an imported function.
545    pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
546        index.index() < self.num_imported_functions
547    }
548
549    /// Convert a `LocalTableIndex` into a `TableIndex`.
550    pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
551        TableIndex::new(self.num_imported_tables + local_table.index())
552    }
553
554    /// Convert a `TableIndex` into a `LocalTableIndex`. Returns None if the
555    /// index is an imported table.
556    pub fn local_table_index(&self, table: TableIndex) -> Option<LocalTableIndex> {
557        table
558            .index()
559            .checked_sub(self.num_imported_tables)
560            .map(LocalTableIndex::new)
561    }
562
563    /// Test whether the given table index is for an imported table.
564    pub fn is_imported_table(&self, index: TableIndex) -> bool {
565        index.index() < self.num_imported_tables
566    }
567
568    /// Convert a `LocalMemoryIndex` into a `MemoryIndex`.
569    pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
570        MemoryIndex::new(self.num_imported_memories + local_memory.index())
571    }
572
573    /// Convert a `MemoryIndex` into a `LocalMemoryIndex`. Returns None if the
574    /// index is an imported memory.
575    pub fn local_memory_index(&self, memory: MemoryIndex) -> Option<LocalMemoryIndex> {
576        memory
577            .index()
578            .checked_sub(self.num_imported_memories)
579            .map(LocalMemoryIndex::new)
580    }
581
582    /// Test whether the given memory index is for an imported memory.
583    pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
584        index.index() < self.num_imported_memories
585    }
586
587    /// Convert a `LocalGlobalIndex` into a `GlobalIndex`.
588    pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
589        GlobalIndex::new(self.num_imported_globals + local_global.index())
590    }
591
592    /// Convert a `GlobalIndex` into a `LocalGlobalIndex`. Returns None if the
593    /// index is an imported global.
594    pub fn local_global_index(&self, global: GlobalIndex) -> Option<LocalGlobalIndex> {
595        global
596            .index()
597            .checked_sub(self.num_imported_globals)
598            .map(LocalGlobalIndex::new)
599    }
600
601    /// Test whether the given global index is for an imported global.
602    pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
603        index.index() < self.num_imported_globals
604    }
605
606    /// Get the type of a global by its index.
607    pub fn global_type(&self, global_index: GlobalIndex) -> Option<GlobalType> {
608        self.globals.get(global_index).copied()
609    }
610
611    /// Convert a `LocalTagIndex` into a `TagIndex`.
612    pub fn tag_index(&self, local_tag: LocalTagIndex) -> TagIndex {
613        TagIndex::new(self.num_imported_tags + local_tag.index())
614    }
615
616    /// Convert a `TagIndex` into a `LocalTagIndex`. Returns None if the
617    /// index is an imported tag.
618    pub fn local_tag_index(&self, tag: TagIndex) -> Option<LocalTagIndex> {
619        tag.index()
620            .checked_sub(self.num_imported_tags)
621            .map(LocalTagIndex::new)
622    }
623
624    /// Test whether the given tag index is for an imported tag.
625    pub fn is_imported_tag(&self, index: TagIndex) -> bool {
626        index.index() < self.num_imported_tags
627    }
628
629    /// Get the Module name
630    pub fn name(&self) -> String {
631        match self.name {
632            Some(ref name) => name.to_string(),
633            None => "<module>".to_string(),
634        }
635    }
636
637    /// Get the imported function types of the module.
638    pub fn imported_function_types(&'_ self) -> impl Iterator<Item = FunctionType> + '_ {
639        self.functions
640            .values()
641            .take(self.num_imported_functions)
642            .map(move |sig_index| self.signatures[*sig_index].clone())
643    }
644
645    /// Get the name of a function by its index.
646    pub fn get_function_name(&self, func_index: FunctionIndex) -> String {
647        self.function_names
648            .get(&func_index)
649            .cloned()
650            .unwrap_or_else(|| format!("function_{}", func_index.as_u32()))
651    }
652}
653
654impl fmt::Display for ModuleInfo {
655    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
656        write!(f, "{}", self.name())
657    }
658}
659
660// Code inspired from
661// https://www.reddit.com/r/rust/comments/9vspv4/extending_iterators_ergonomically/
662
663/// This iterator allows us to iterate over the exports
664/// and offer nice API ergonomics over it.
665pub struct ExportsIterator<I: Iterator<Item = ExportType> + Sized> {
666    iter: I,
667    size: usize,
668}
669
670impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
671    /// Create a new `ExportsIterator` for a given iterator and size
672    pub fn new(iter: I, size: usize) -> Self {
673        Self { iter, size }
674    }
675}
676
677impl<I: Iterator<Item = ExportType> + Sized> ExactSizeIterator for ExportsIterator<I> {
678    // We can easily calculate the remaining number of iterations.
679    fn len(&self) -> usize {
680        self.size
681    }
682}
683
684impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
685    /// Get only the functions
686    pub fn functions(self) -> impl Iterator<Item = ExportType<FunctionType>> + Sized {
687        self.iter.filter_map(|extern_| match extern_.ty() {
688            ExternType::Function(ty) => Some(ExportType::new(extern_.name(), ty.clone())),
689            _ => None,
690        })
691    }
692    /// Get only the memories
693    pub fn memories(self) -> impl Iterator<Item = ExportType<MemoryType>> + Sized {
694        self.iter.filter_map(|extern_| match extern_.ty() {
695            ExternType::Memory(ty) => Some(ExportType::new(extern_.name(), *ty)),
696            _ => None,
697        })
698    }
699    /// Get only the tables
700    pub fn tables(self) -> impl Iterator<Item = ExportType<TableType>> + Sized {
701        self.iter.filter_map(|extern_| match extern_.ty() {
702            ExternType::Table(ty) => Some(ExportType::new(extern_.name(), *ty)),
703            _ => None,
704        })
705    }
706    /// Get only the globals
707    pub fn globals(self) -> impl Iterator<Item = ExportType<GlobalType>> + Sized {
708        self.iter.filter_map(|extern_| match extern_.ty() {
709            ExternType::Global(ty) => Some(ExportType::new(extern_.name(), *ty)),
710            _ => None,
711        })
712    }
713    /// Get only the tags
714    pub fn tags(self) -> impl Iterator<Item = ExportType<TagType>> + Sized {
715        self.iter.filter_map(|extern_| match extern_.ty() {
716            ExternType::Tag(ty) => Some(ExportType::new(extern_.name(), ty.clone())),
717            _ => None,
718        })
719    }
720}
721
722impl<I: Iterator<Item = ExportType> + Sized> Iterator for ExportsIterator<I> {
723    type Item = ExportType;
724    fn next(&mut self) -> Option<Self::Item> {
725        self.iter.next()
726    }
727}
728
729/// This iterator allows us to iterate over the imports
730/// and offer nice API ergonomics over it.
731pub struct ImportsIterator<I: Iterator<Item = ImportType> + Sized> {
732    iter: I,
733    size: usize,
734}
735
736impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
737    /// Create a new `ImportsIterator` for a given iterator and size
738    pub fn new(iter: I, size: usize) -> Self {
739        Self { iter, size }
740    }
741}
742
743impl<I: Iterator<Item = ImportType> + Sized> ExactSizeIterator for ImportsIterator<I> {
744    // We can easily calculate the remaining number of iterations.
745    fn len(&self) -> usize {
746        self.size
747    }
748}
749
750impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
751    /// Get only the functions
752    pub fn functions(self) -> impl Iterator<Item = ImportType<FunctionType>> + Sized {
753        self.iter.filter_map(|extern_| match extern_.ty() {
754            ExternType::Function(ty) => Some(ImportType::new(
755                extern_.module(),
756                extern_.name(),
757                ty.clone(),
758            )),
759            _ => None,
760        })
761    }
762    /// Get only the memories
763    pub fn memories(self) -> impl Iterator<Item = ImportType<MemoryType>> + Sized {
764        self.iter.filter_map(|extern_| match extern_.ty() {
765            ExternType::Memory(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
766            _ => None,
767        })
768    }
769    /// Get only the tables
770    pub fn tables(self) -> impl Iterator<Item = ImportType<TableType>> + Sized {
771        self.iter.filter_map(|extern_| match extern_.ty() {
772            ExternType::Table(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
773            _ => None,
774        })
775    }
776    /// Get only the globals
777    pub fn globals(self) -> impl Iterator<Item = ImportType<GlobalType>> + Sized {
778        self.iter.filter_map(|extern_| match extern_.ty() {
779            ExternType::Global(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
780            _ => None,
781        })
782    }
783    /// Get only the tags
784    pub fn tags(self) -> impl Iterator<Item = ImportType<TagType>> + Sized {
785        self.iter.filter_map(|extern_| match extern_.ty() {
786            ExternType::Tag(ty) => Some(ImportType::new(
787                extern_.module(),
788                extern_.name(),
789                ty.clone(),
790            )),
791            _ => None,
792        })
793    }
794}
795
796impl<I: Iterator<Item = ImportType> + Sized> Iterator for ImportsIterator<I> {
797    type Item = ImportType;
798    fn next(&mut self) -> Option<Self::Item> {
799        self.iter.next()
800    }
801}