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::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#[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 pub module: String,
58 pub field: String,
60 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 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#[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 #[cfg_attr(feature = "enable-serde", serde(skip_serializing, skip_deserializing))]
119 pub id: ModuleId,
120
121 pub hash: Option<ModuleHash>,
123
124 pub name: Option<String>,
126
127 #[cfg_attr(feature = "enable-serde", serde(with = "serde_imports"))]
133 pub imports: IndexMap<ImportKey, ImportIndex>,
134
135 pub exports: IndexMap<String, ExportIndex>,
137
138 pub start_function: Option<FunctionIndex>,
140
141 pub table_initializers: Vec<TableInitializer>,
143
144 pub passive_elements: HashMap<ElemIndex, Box<[FunctionIndex]>>,
146
147 pub passive_data: HashMap<DataIndex, Box<[u8]>>,
149
150 pub global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
152
153 pub function_names: HashMap<FunctionIndex, String>,
155
156 pub signatures: PrimaryMap<SignatureIndex, FunctionType>,
158
159 pub signature_hashes: PrimaryMap<SignatureIndex, SignatureHash>,
161
162 pub functions: PrimaryMap<FunctionIndex, SignatureIndex>,
164
165 pub tables: PrimaryMap<TableIndex, TableType>,
167
168 pub memories: PrimaryMap<MemoryIndex, MemoryType>,
170
171 pub globals: PrimaryMap<GlobalIndex, GlobalType>,
173
174 pub tags: PrimaryMap<TagIndex, SignatureIndex>,
176
177 pub custom_sections: IndexMap<String, CustomSectionIndex>,
179
180 pub custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
182
183 pub num_imported_functions: usize,
185
186 pub num_imported_tables: usize,
188
189 pub num_imported_memories: usize,
191
192 pub num_imported_tags: usize,
194
195 pub num_imported_globals: usize,
197}
198
199#[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
327impl 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 pub fn new() -> Self {
361 Default::default()
362 }
363
364 pub fn hash(&self) -> Option<ModuleHash> {
366 self.hash
367 }
368
369 pub fn hash_string(&self) -> Option<String> {
371 self.hash.map(|m| m.to_string())
372 }
373
374 pub fn validate_signature_hashes(&self) -> WasmResult<()> {
376 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 pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
393 self.passive_elements.get(&index).map(|es| &**es)
394 }
395
396 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 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 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 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 pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
504 FunctionIndex::new(self.num_imported_functions + local_func.index())
505 }
506
507 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 pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
517 index.index() < self.num_imported_functions
518 }
519
520 pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
522 TableIndex::new(self.num_imported_tables + local_table.index())
523 }
524
525 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 pub fn is_imported_table(&self, index: TableIndex) -> bool {
536 index.index() < self.num_imported_tables
537 }
538
539 pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
541 MemoryIndex::new(self.num_imported_memories + local_memory.index())
542 }
543
544 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 pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
555 index.index() < self.num_imported_memories
556 }
557
558 pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
560 GlobalIndex::new(self.num_imported_globals + local_global.index())
561 }
562
563 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 pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
574 index.index() < self.num_imported_globals
575 }
576
577 pub fn global_type(&self, global_index: GlobalIndex) -> Option<GlobalType> {
579 self.globals.get(global_index).copied()
580 }
581
582 pub fn tag_index(&self, local_tag: LocalTagIndex) -> TagIndex {
584 TagIndex::new(self.num_imported_tags + local_tag.index())
585 }
586
587 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 pub fn is_imported_tag(&self, index: TagIndex) -> bool {
597 index.index() < self.num_imported_tags
598 }
599
600 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 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 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
631pub struct ExportsIterator<I: Iterator<Item = ExportType> + Sized> {
637 iter: I,
638 size: usize,
639}
640
641impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
642 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 fn len(&self) -> usize {
651 self.size
652 }
653}
654
655impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
656 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 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 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 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 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
700pub struct ImportsIterator<I: Iterator<Item = ImportType> + Sized> {
703 iter: I,
704 size: usize,
705}
706
707impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
708 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 fn len(&self) -> usize {
717 self.size
718 }
719}
720
721impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
722 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 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 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 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 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}