1use 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#[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 pub module: String,
59 pub field: String,
61 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 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#[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 #[cfg_attr(feature = "enable-serde", serde(skip_serializing, skip_deserializing))]
120 pub id: ModuleId,
121
122 pub hash: Option<ModuleHash>,
124
125 pub name: Option<String>,
127
128 #[cfg_attr(feature = "enable-serde", serde(with = "serde_imports"))]
134 pub imports: IndexMap<ImportKey, ImportIndex>,
135
136 pub exports: IndexMap<String, ExportIndex>,
138
139 pub start_function: Option<FunctionIndex>,
141
142 pub table_initializers: Vec<TableInitializer>,
144
145 pub passive_elements: HashMap<ElemIndex, Box<[FunctionIndex]>>,
147
148 pub passive_data: HashMap<DataIndex, Arc<[u8]>>,
156
157 pub global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
159
160 pub function_names: HashMap<FunctionIndex, String>,
162
163 pub signatures: PrimaryMap<SignatureIndex, FunctionType>,
165
166 pub signature_hashes: PrimaryMap<SignatureIndex, SignatureHash>,
168
169 pub functions: PrimaryMap<FunctionIndex, SignatureIndex>,
171
172 pub tables: PrimaryMap<TableIndex, TableType>,
174
175 pub memories: PrimaryMap<MemoryIndex, MemoryType>,
177
178 pub globals: PrimaryMap<GlobalIndex, GlobalType>,
180
181 pub tags: PrimaryMap<TagIndex, SignatureIndex>,
183
184 pub custom_sections: IndexMap<String, CustomSectionIndex>,
186
187 pub custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
189
190 pub num_imported_functions: usize,
192
193 pub num_imported_tables: usize,
195
196 pub num_imported_memories: usize,
198
199 pub num_imported_tags: usize,
201
202 pub num_imported_globals: usize,
204}
205
206const _: () = 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#[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 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
356impl 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 pub fn new() -> Self {
390 Default::default()
391 }
392
393 pub fn hash(&self) -> Option<ModuleHash> {
395 self.hash
396 }
397
398 pub fn hash_string(&self) -> Option<String> {
400 self.hash.map(|m| m.to_string())
401 }
402
403 pub fn validate_signature_hashes(&self) -> WasmResult<()> {
405 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 pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
422 self.passive_elements.get(&index).map(|es| &**es)
423 }
424
425 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 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 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 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 pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
533 FunctionIndex::new(self.num_imported_functions + local_func.index())
534 }
535
536 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 pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
546 index.index() < self.num_imported_functions
547 }
548
549 pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
551 TableIndex::new(self.num_imported_tables + local_table.index())
552 }
553
554 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 pub fn is_imported_table(&self, index: TableIndex) -> bool {
565 index.index() < self.num_imported_tables
566 }
567
568 pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
570 MemoryIndex::new(self.num_imported_memories + local_memory.index())
571 }
572
573 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 pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
584 index.index() < self.num_imported_memories
585 }
586
587 pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
589 GlobalIndex::new(self.num_imported_globals + local_global.index())
590 }
591
592 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 pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
603 index.index() < self.num_imported_globals
604 }
605
606 pub fn global_type(&self, global_index: GlobalIndex) -> Option<GlobalType> {
608 self.globals.get(global_index).copied()
609 }
610
611 pub fn tag_index(&self, local_tag: LocalTagIndex) -> TagIndex {
613 TagIndex::new(self.num_imported_tags + local_tag.index())
614 }
615
616 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 pub fn is_imported_tag(&self, index: TagIndex) -> bool {
626 index.index() < self.num_imported_tags
627 }
628
629 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 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 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
660pub struct ExportsIterator<I: Iterator<Item = ExportType> + Sized> {
666 iter: I,
667 size: usize,
668}
669
670impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
671 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 fn len(&self) -> usize {
680 self.size
681 }
682}
683
684impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
685 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 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 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 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 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
729pub struct ImportsIterator<I: Iterator<Item = ImportType> + Sized> {
732 iter: I,
733 size: usize,
734}
735
736impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
737 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 fn len(&self) -> usize {
746 self.size
747 }
748}
749
750impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
751 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 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 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 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 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}