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: BTreeMap<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
206#[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
335impl 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 pub fn new() -> Self {
369 Default::default()
370 }
371
372 pub fn hash(&self) -> Option<ModuleHash> {
374 self.hash
375 }
376
377 pub fn hash_string(&self) -> Option<String> {
379 self.hash.map(|m| m.to_string())
380 }
381
382 pub fn validate_signature_hashes(&self) -> WasmResult<()> {
384 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 pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
401 self.passive_elements.get(&index).map(|es| &**es)
402 }
403
404 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 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 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 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 pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
512 FunctionIndex::new(self.num_imported_functions + local_func.index())
513 }
514
515 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 pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
525 index.index() < self.num_imported_functions
526 }
527
528 pub fn local_func_count(&self) -> usize {
530 self.functions.len() - self.num_imported_functions
531 }
532
533 pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
535 TableIndex::new(self.num_imported_tables + local_table.index())
536 }
537
538 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 pub fn is_imported_table(&self, index: TableIndex) -> bool {
549 index.index() < self.num_imported_tables
550 }
551
552 pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
554 MemoryIndex::new(self.num_imported_memories + local_memory.index())
555 }
556
557 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 pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
568 index.index() < self.num_imported_memories
569 }
570
571 pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
573 GlobalIndex::new(self.num_imported_globals + local_global.index())
574 }
575
576 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 pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
587 index.index() < self.num_imported_globals
588 }
589
590 pub fn global_type(&self, global_index: GlobalIndex) -> Option<GlobalType> {
592 self.globals.get(global_index).copied()
593 }
594
595 pub fn tag_index(&self, local_tag: LocalTagIndex) -> TagIndex {
597 TagIndex::new(self.num_imported_tags + local_tag.index())
598 }
599
600 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 pub fn is_imported_tag(&self, index: TagIndex) -> bool {
610 index.index() < self.num_imported_tags
611 }
612
613 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 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 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
644pub struct ExportsIterator<I: Iterator<Item = ExportType> + Sized> {
650 iter: I,
651 size: usize,
652}
653
654impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
655 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 fn len(&self) -> usize {
664 self.size
665 }
666}
667
668impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
669 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 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 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 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 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
713pub struct ImportsIterator<I: Iterator<Item = ImportType> + Sized> {
716 iter: I,
717 size: usize,
718}
719
720impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
721 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 fn len(&self) -> usize {
730 self.size
731 }
732}
733
734impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
735 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 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 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 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 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}