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