Skip to main content

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: BTreeMap<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/// Mirror version of ModuleInfo that can derive rkyv traits
207#[derive(Debug, RkyvSerialize, RkyvDeserialize, Archive)]
208#[rkyv(derive(Debug))]
209pub struct ArchivableModuleInfo {
210    name: Option<String>,
211    hash: Option<ModuleHash>,
212    imports: IndexMap<ImportKey, ImportIndex>,
213    exports: IndexMap<String, ExportIndex>,
214    start_function: Option<FunctionIndex>,
215    table_initializers: Vec<TableInitializer>,
216    passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
217    passive_data: BTreeMap<DataIndex, Arc<[u8]>>,
218    global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
219    function_names: BTreeMap<FunctionIndex, String>,
220    signatures: PrimaryMap<SignatureIndex, FunctionType>,
221    signature_hashes: PrimaryMap<SignatureIndex, SignatureHash>,
222    functions: PrimaryMap<FunctionIndex, SignatureIndex>,
223    tables: PrimaryMap<TableIndex, TableType>,
224    memories: PrimaryMap<MemoryIndex, MemoryType>,
225    globals: PrimaryMap<GlobalIndex, GlobalType>,
226    tags: PrimaryMap<TagIndex, SignatureIndex>,
227    custom_sections: IndexMap<String, CustomSectionIndex>,
228    custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
229    num_imported_functions: usize,
230    num_imported_tables: usize,
231    num_imported_tags: usize,
232    num_imported_memories: usize,
233    num_imported_globals: usize,
234}
235
236impl From<ModuleInfo> for ArchivableModuleInfo {
237    fn from(it: ModuleInfo) -> Self {
238        Self {
239            name: it.name,
240            hash: it.hash,
241            imports: it.imports,
242            exports: it.exports,
243            start_function: it.start_function,
244            table_initializers: it.table_initializers,
245            passive_elements: it.passive_elements.into_iter().collect(),
246            passive_data: it.passive_data,
247            global_initializers: it.global_initializers,
248            function_names: it.function_names.into_iter().collect(),
249            signatures: it.signatures,
250            signature_hashes: it.signature_hashes,
251            functions: it.functions,
252            tables: it.tables,
253            memories: it.memories,
254            globals: it.globals,
255            tags: it.tags,
256            custom_sections: it.custom_sections,
257            custom_sections_data: it.custom_sections_data,
258            num_imported_functions: it.num_imported_functions,
259            num_imported_tables: it.num_imported_tables,
260            num_imported_tags: it.num_imported_tags,
261            num_imported_memories: it.num_imported_memories,
262            num_imported_globals: it.num_imported_globals,
263        }
264    }
265}
266
267impl From<ArchivableModuleInfo> for ModuleInfo {
268    fn from(it: ArchivableModuleInfo) -> Self {
269        Self {
270            id: Default::default(),
271            name: it.name,
272            hash: it.hash,
273            imports: it.imports,
274            exports: it.exports,
275            start_function: it.start_function,
276            table_initializers: it.table_initializers,
277            passive_elements: it.passive_elements.into_iter().collect(),
278            passive_data: it.passive_data,
279            global_initializers: it.global_initializers,
280            function_names: it.function_names.into_iter().collect(),
281            signatures: it.signatures,
282            signature_hashes: it.signature_hashes,
283            functions: it.functions,
284            tables: it.tables,
285            memories: it.memories,
286            globals: it.globals,
287            tags: it.tags,
288            custom_sections: it.custom_sections,
289            custom_sections_data: it.custom_sections_data,
290            num_imported_functions: it.num_imported_functions,
291            num_imported_tables: it.num_imported_tables,
292            num_imported_tags: it.num_imported_tags,
293            num_imported_memories: it.num_imported_memories,
294            num_imported_globals: it.num_imported_globals,
295        }
296    }
297}
298
299impl From<&ModuleInfo> for ArchivableModuleInfo {
300    fn from(it: &ModuleInfo) -> Self {
301        Self::from(it.clone())
302    }
303}
304
305impl Archive for ModuleInfo {
306    type Archived = <ArchivableModuleInfo as Archive>::Archived;
307    type Resolver = <ArchivableModuleInfo as Archive>::Resolver;
308
309    fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
310        ArchivableModuleInfo::from(self).resolve(resolver, out)
311    }
312}
313
314impl<S: rkyv::ser::Allocator + rkyv::ser::Writer + rkyv::ser::Sharing + Fallible + ?Sized>
315    RkyvSerialize<S> for ModuleInfo
316where
317    <S as Fallible>::Error: rkyv::rancor::Source + rkyv::rancor::Trace,
318{
319    fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
320        ArchivableModuleInfo::from(self).serialize(serializer)
321    }
322}
323
324impl<D: rkyv::de::Pooling + Fallible + ?Sized> RkyvDeserialize<ModuleInfo, D>
325    for ArchivedArchivableModuleInfo
326where
327    D::Error: Source + Trace,
328{
329    fn deserialize(&self, deserializer: &mut D) -> Result<ModuleInfo, D::Error> {
330        let archived = RkyvDeserialize::<ArchivableModuleInfo, D>::deserialize(self, deserializer)?;
331        Ok(ModuleInfo::from(archived))
332    }
333}
334
335// For test serialization correctness, everything except module id should be same
336impl PartialEq for ModuleInfo {
337    fn eq(&self, other: &Self) -> bool {
338        self.name == other.name
339            && self.imports == other.imports
340            && self.exports == other.exports
341            && self.start_function == other.start_function
342            && self.table_initializers == other.table_initializers
343            && self.passive_elements == other.passive_elements
344            && self.passive_data == other.passive_data
345            && self.global_initializers == other.global_initializers
346            && self.function_names == other.function_names
347            && self.signatures == other.signatures
348            && self.signature_hashes == other.signature_hashes
349            && self.functions == other.functions
350            && self.tables == other.tables
351            && self.memories == other.memories
352            && self.globals == other.globals
353            && self.tags == other.tags
354            && self.custom_sections == other.custom_sections
355            && self.custom_sections_data == other.custom_sections_data
356            && self.num_imported_functions == other.num_imported_functions
357            && self.num_imported_tables == other.num_imported_tables
358            && self.num_imported_tags == other.num_imported_tags
359            && self.num_imported_memories == other.num_imported_memories
360            && self.num_imported_globals == other.num_imported_globals
361    }
362}
363
364impl Eq for ModuleInfo {}
365
366impl ModuleInfo {
367    /// Allocates the module data structures.
368    pub fn new() -> Self {
369        Default::default()
370    }
371
372    /// Returns the module hash if available
373    pub fn hash(&self) -> Option<ModuleHash> {
374        self.hash
375    }
376
377    /// Returns the module hash as String if available
378    pub fn hash_string(&self) -> Option<String> {
379        self.hash.map(|m| m.to_string())
380    }
381
382    /// Validates invariants for the precomputed signature hashes.
383    pub fn validate_signature_hashes(&self) -> WasmResult<()> {
384        // TODO: the signatures are not distinct, thus we cannot just validate signature_hashes.
385        if self
386            .signatures
387            .iter()
388            .map(|(_, signature)| signature)
389            .unique()
390            .map(|signature| signature.signature_hash())
391            .all_unique()
392        {
393            Ok(())
394        } else {
395            Err(WasmError::Generic("signature hash collision".to_string()))
396        }
397    }
398
399    /// Get the given passive element, if it exists.
400    pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
401        self.passive_elements.get(&index).map(|es| &**es)
402    }
403
404    /// Get the exported signatures of the module
405    pub fn exported_signatures(&self) -> Vec<FunctionType> {
406        self.exports
407            .iter()
408            .filter_map(|(_name, export_index)| match export_index {
409                ExportIndex::Function(i) => {
410                    let signature = self.functions.get(*i).unwrap();
411                    let func_type = self.signatures.get(*signature).unwrap();
412                    Some(func_type.clone())
413                }
414                _ => None,
415            })
416            .collect::<Vec<FunctionType>>()
417    }
418
419    /// Get the export types of the module
420    pub fn exports(&'_ self) -> ExportsIterator<Box<dyn Iterator<Item = ExportType> + '_>> {
421        let iter = self.exports.iter().map(move |(name, export_index)| {
422            let extern_type = match export_index {
423                ExportIndex::Function(i) => {
424                    let signature = self.functions.get(*i).unwrap();
425                    let func_type = self.signatures.get(*signature).unwrap();
426                    ExternType::Function(func_type.clone())
427                }
428                ExportIndex::Table(i) => {
429                    let table_type = self.tables.get(*i).unwrap();
430                    ExternType::Table(*table_type)
431                }
432                ExportIndex::Memory(i) => {
433                    let memory_type = self.memories.get(*i).unwrap();
434                    ExternType::Memory(*memory_type)
435                }
436                ExportIndex::Global(i) => {
437                    let global_type = self.globals.get(*i).unwrap();
438                    ExternType::Global(*global_type)
439                }
440                ExportIndex::Tag(i) => {
441                    let signature = self.tags.get(*i).unwrap();
442                    let tag_type = self.signatures.get(*signature).unwrap();
443
444                    ExternType::Tag(TagType {
445                        kind: crate::types::TagKind::Exception,
446                        params: tag_type.params().into(),
447                    })
448                }
449            };
450            ExportType::new(name, extern_type)
451        });
452        ExportsIterator::new(Box::new(iter), self.exports.len())
453    }
454
455    /// Get the import types of the module
456    pub fn imports(&'_ self) -> ImportsIterator<Box<dyn Iterator<Item = ImportType> + '_>> {
457        let iter =
458            self.imports
459                .iter()
460                .map(move |(ImportKey { module, field, .. }, import_index)| {
461                    let extern_type = match import_index {
462                        ImportIndex::Function(i) => {
463                            let signature = self.functions.get(*i).unwrap();
464                            let func_type = self.signatures.get(*signature).unwrap();
465                            ExternType::Function(func_type.clone())
466                        }
467                        ImportIndex::Table(i) => {
468                            let table_type = self.tables.get(*i).unwrap();
469                            ExternType::Table(*table_type)
470                        }
471                        ImportIndex::Memory(i) => {
472                            let memory_type = self.memories.get(*i).unwrap();
473                            ExternType::Memory(*memory_type)
474                        }
475                        ImportIndex::Global(i) => {
476                            let global_type = self.globals.get(*i).unwrap();
477                            ExternType::Global(*global_type)
478                        }
479                        ImportIndex::Tag(i) => {
480                            let tag_type = self.tags.get(*i).unwrap();
481                            let func_type = self.signatures.get(*tag_type).unwrap();
482                            ExternType::Tag(TagType::from_fn_type(
483                                crate::TagKind::Exception,
484                                func_type.clone(),
485                            ))
486                        }
487                    };
488                    ImportType::new(module, field, extern_type)
489                });
490        ImportsIterator::new(Box::new(iter), self.imports.len())
491    }
492
493    /// Get the custom sections of the module given a `name`.
494    pub fn custom_sections<'a>(
495        &'a self,
496        name: &'a str,
497    ) -> Box<impl Iterator<Item = Box<[u8]>> + 'a> {
498        Box::new(
499            self.custom_sections
500                .iter()
501                .filter_map(move |(section_name, section_index)| {
502                    if name != section_name {
503                        return None;
504                    }
505                    Some(self.custom_sections_data[*section_index].clone())
506                }),
507        )
508    }
509
510    /// Convert a `LocalFunctionIndex` into a `FunctionIndex`.
511    pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
512        FunctionIndex::new(self.num_imported_functions + local_func.index())
513    }
514
515    /// Convert a `FunctionIndex` into a `LocalFunctionIndex`. Returns None if the
516    /// index is an imported function.
517    pub fn local_func_index(&self, func: FunctionIndex) -> Option<LocalFunctionIndex> {
518        func.index()
519            .checked_sub(self.num_imported_functions)
520            .map(LocalFunctionIndex::new)
521    }
522
523    /// Test whether the given function index is for an imported function.
524    pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
525        index.index() < self.num_imported_functions
526    }
527
528    /// Get number of local functions.
529    pub fn local_func_count(&self) -> usize {
530        self.functions.len() - self.num_imported_functions
531    }
532
533    /// Convert a `LocalTableIndex` into a `TableIndex`.
534    pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
535        TableIndex::new(self.num_imported_tables + local_table.index())
536    }
537
538    /// Convert a `TableIndex` into a `LocalTableIndex`. Returns None if the
539    /// index is an imported table.
540    pub fn local_table_index(&self, table: TableIndex) -> Option<LocalTableIndex> {
541        table
542            .index()
543            .checked_sub(self.num_imported_tables)
544            .map(LocalTableIndex::new)
545    }
546
547    /// Test whether the given table index is for an imported table.
548    pub fn is_imported_table(&self, index: TableIndex) -> bool {
549        index.index() < self.num_imported_tables
550    }
551
552    /// Convert a `LocalMemoryIndex` into a `MemoryIndex`.
553    pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
554        MemoryIndex::new(self.num_imported_memories + local_memory.index())
555    }
556
557    /// Convert a `MemoryIndex` into a `LocalMemoryIndex`. Returns None if the
558    /// index is an imported memory.
559    pub fn local_memory_index(&self, memory: MemoryIndex) -> Option<LocalMemoryIndex> {
560        memory
561            .index()
562            .checked_sub(self.num_imported_memories)
563            .map(LocalMemoryIndex::new)
564    }
565
566    /// Test whether the given memory index is for an imported memory.
567    pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
568        index.index() < self.num_imported_memories
569    }
570
571    /// Convert a `LocalGlobalIndex` into a `GlobalIndex`.
572    pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
573        GlobalIndex::new(self.num_imported_globals + local_global.index())
574    }
575
576    /// Convert a `GlobalIndex` into a `LocalGlobalIndex`. Returns None if the
577    /// index is an imported global.
578    pub fn local_global_index(&self, global: GlobalIndex) -> Option<LocalGlobalIndex> {
579        global
580            .index()
581            .checked_sub(self.num_imported_globals)
582            .map(LocalGlobalIndex::new)
583    }
584
585    /// Test whether the given global index is for an imported global.
586    pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
587        index.index() < self.num_imported_globals
588    }
589
590    /// Get the type of a global by its index.
591    pub fn global_type(&self, global_index: GlobalIndex) -> Option<GlobalType> {
592        self.globals.get(global_index).copied()
593    }
594
595    /// Convert a `LocalTagIndex` into a `TagIndex`.
596    pub fn tag_index(&self, local_tag: LocalTagIndex) -> TagIndex {
597        TagIndex::new(self.num_imported_tags + local_tag.index())
598    }
599
600    /// Convert a `TagIndex` into a `LocalTagIndex`. Returns None if the
601    /// index is an imported tag.
602    pub fn local_tag_index(&self, tag: TagIndex) -> Option<LocalTagIndex> {
603        tag.index()
604            .checked_sub(self.num_imported_tags)
605            .map(LocalTagIndex::new)
606    }
607
608    /// Test whether the given tag index is for an imported tag.
609    pub fn is_imported_tag(&self, index: TagIndex) -> bool {
610        index.index() < self.num_imported_tags
611    }
612
613    /// Get the Module name
614    pub fn name(&self) -> String {
615        match self.name {
616            Some(ref name) => name.to_string(),
617            None => "<module>".to_string(),
618        }
619    }
620
621    /// Get the imported function types of the module.
622    pub fn imported_function_types(&'_ self) -> impl Iterator<Item = FunctionType> + '_ {
623        self.functions
624            .values()
625            .take(self.num_imported_functions)
626            .map(move |sig_index| self.signatures[*sig_index].clone())
627    }
628
629    /// Get the name of a function by its index.
630    pub fn get_function_name(&self, func_index: FunctionIndex) -> String {
631        self.function_names
632            .get(&func_index)
633            .cloned()
634            .unwrap_or_else(|| format!("function_{}", func_index.as_u32()))
635    }
636}
637
638impl fmt::Display for ModuleInfo {
639    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
640        write!(f, "{}", self.name())
641    }
642}
643
644// Code inspired from
645// https://www.reddit.com/r/rust/comments/9vspv4/extending_iterators_ergonomically/
646
647/// This iterator allows us to iterate over the exports
648/// and offer nice API ergonomics over it.
649pub struct ExportsIterator<I: Iterator<Item = ExportType> + Sized> {
650    iter: I,
651    size: usize,
652}
653
654impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
655    /// Create a new `ExportsIterator` for a given iterator and size
656    pub fn new(iter: I, size: usize) -> Self {
657        Self { iter, size }
658    }
659}
660
661impl<I: Iterator<Item = ExportType> + Sized> ExactSizeIterator for ExportsIterator<I> {
662    // We can easily calculate the remaining number of iterations.
663    fn len(&self) -> usize {
664        self.size
665    }
666}
667
668impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
669    /// Get only the functions
670    pub fn functions(self) -> impl Iterator<Item = ExportType<FunctionType>> + Sized {
671        self.iter.filter_map(|extern_| match extern_.ty() {
672            ExternType::Function(ty) => Some(ExportType::new(extern_.name(), ty.clone())),
673            _ => None,
674        })
675    }
676    /// Get only the memories
677    pub fn memories(self) -> impl Iterator<Item = ExportType<MemoryType>> + Sized {
678        self.iter.filter_map(|extern_| match extern_.ty() {
679            ExternType::Memory(ty) => Some(ExportType::new(extern_.name(), *ty)),
680            _ => None,
681        })
682    }
683    /// Get only the tables
684    pub fn tables(self) -> impl Iterator<Item = ExportType<TableType>> + Sized {
685        self.iter.filter_map(|extern_| match extern_.ty() {
686            ExternType::Table(ty) => Some(ExportType::new(extern_.name(), *ty)),
687            _ => None,
688        })
689    }
690    /// Get only the globals
691    pub fn globals(self) -> impl Iterator<Item = ExportType<GlobalType>> + Sized {
692        self.iter.filter_map(|extern_| match extern_.ty() {
693            ExternType::Global(ty) => Some(ExportType::new(extern_.name(), *ty)),
694            _ => None,
695        })
696    }
697    /// Get only the tags
698    pub fn tags(self) -> impl Iterator<Item = ExportType<TagType>> + Sized {
699        self.iter.filter_map(|extern_| match extern_.ty() {
700            ExternType::Tag(ty) => Some(ExportType::new(extern_.name(), ty.clone())),
701            _ => None,
702        })
703    }
704}
705
706impl<I: Iterator<Item = ExportType> + Sized> Iterator for ExportsIterator<I> {
707    type Item = ExportType;
708    fn next(&mut self) -> Option<Self::Item> {
709        self.iter.next()
710    }
711}
712
713/// This iterator allows us to iterate over the imports
714/// and offer nice API ergonomics over it.
715pub struct ImportsIterator<I: Iterator<Item = ImportType> + Sized> {
716    iter: I,
717    size: usize,
718}
719
720impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
721    /// Create a new `ImportsIterator` for a given iterator and size
722    pub fn new(iter: I, size: usize) -> Self {
723        Self { iter, size }
724    }
725}
726
727impl<I: Iterator<Item = ImportType> + Sized> ExactSizeIterator for ImportsIterator<I> {
728    // We can easily calculate the remaining number of iterations.
729    fn len(&self) -> usize {
730        self.size
731    }
732}
733
734impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
735    /// Get only the functions
736    pub fn functions(self) -> impl Iterator<Item = ImportType<FunctionType>> + Sized {
737        self.iter.filter_map(|extern_| match extern_.ty() {
738            ExternType::Function(ty) => Some(ImportType::new(
739                extern_.module(),
740                extern_.name(),
741                ty.clone(),
742            )),
743            _ => None,
744        })
745    }
746    /// Get only the memories
747    pub fn memories(self) -> impl Iterator<Item = ImportType<MemoryType>> + Sized {
748        self.iter.filter_map(|extern_| match extern_.ty() {
749            ExternType::Memory(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
750            _ => None,
751        })
752    }
753    /// Get only the tables
754    pub fn tables(self) -> impl Iterator<Item = ImportType<TableType>> + Sized {
755        self.iter.filter_map(|extern_| match extern_.ty() {
756            ExternType::Table(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
757            _ => None,
758        })
759    }
760    /// Get only the globals
761    pub fn globals(self) -> impl Iterator<Item = ImportType<GlobalType>> + Sized {
762        self.iter.filter_map(|extern_| match extern_.ty() {
763            ExternType::Global(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
764            _ => None,
765        })
766    }
767    /// Get only the tags
768    pub fn tags(self) -> impl Iterator<Item = ImportType<TagType>> + Sized {
769        self.iter.filter_map(|extern_| match extern_.ty() {
770            ExternType::Tag(ty) => Some(ImportType::new(
771                extern_.module(),
772                extern_.name(),
773                ty.clone(),
774            )),
775            _ => None,
776        })
777    }
778}
779
780impl<I: Iterator<Item = ImportType> + Sized> Iterator for ImportsIterator<I> {
781    type Item = ImportType;
782    fn next(&mut self) -> Option<Self::Item> {
783        self.iter.next()
784    }
785}