1use crate::entity::{EntityRef, PrimaryMap};
8use crate::{
9 CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, ExportType, ExternType, FunctionIndex,
10 FunctionType, GlobalIndex, GlobalInit, GlobalType, ImportIndex, ImportType, LocalFunctionIndex,
11 LocalGlobalIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, ModuleHash,
12 SignatureIndex, TableIndex, TableInitializer, TableType,
13};
14
15use indexmap::IndexMap;
16use rkyv::{
17 de::SharedDeserializeRegistry, ser::ScratchSpace, ser::Serializer,
18 ser::SharedSerializeRegistry, Archive, Archived, CheckBytes, Deserialize as RkyvDeserialize,
19 Fallible, Serialize as RkyvSerialize,
20};
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#[archive_attr(derive(CheckBytes, 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#[archive_attr(derive(CheckBytes, 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 functions: PrimaryMap<FunctionIndex, SignatureIndex>,
161
162 pub tables: PrimaryMap<TableIndex, TableType>,
164
165 pub memories: PrimaryMap<MemoryIndex, MemoryType>,
167
168 pub globals: PrimaryMap<GlobalIndex, GlobalType>,
170
171 pub custom_sections: IndexMap<String, CustomSectionIndex>,
173
174 pub custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
176
177 pub num_imported_functions: usize,
179
180 pub num_imported_tables: usize,
182
183 pub num_imported_memories: usize,
185
186 pub num_imported_globals: usize,
188}
189
190#[derive(Debug, RkyvSerialize, RkyvDeserialize, Archive)]
192#[archive_attr(derive(CheckBytes, Debug))]
193pub struct ArchivableModuleInfo {
194 name: Option<String>,
195 hash: Option<ModuleHash>,
196 imports: IndexMap<ImportKey, ImportIndex>,
197 exports: IndexMap<String, ExportIndex>,
198 start_function: Option<FunctionIndex>,
199 table_initializers: Vec<TableInitializer>,
200 passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
201 passive_data: BTreeMap<DataIndex, Box<[u8]>>,
202 global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
203 function_names: BTreeMap<FunctionIndex, String>,
204 signatures: PrimaryMap<SignatureIndex, FunctionType>,
205 functions: PrimaryMap<FunctionIndex, SignatureIndex>,
206 tables: PrimaryMap<TableIndex, TableType>,
207 memories: PrimaryMap<MemoryIndex, MemoryType>,
208 globals: PrimaryMap<GlobalIndex, GlobalType>,
209 custom_sections: IndexMap<String, CustomSectionIndex>,
210 custom_sections_data: PrimaryMap<CustomSectionIndex, Box<[u8]>>,
211 num_imported_functions: usize,
212 num_imported_tables: usize,
213 num_imported_memories: usize,
214 num_imported_globals: usize,
215}
216
217impl From<ModuleInfo> for ArchivableModuleInfo {
218 fn from(it: ModuleInfo) -> Self {
219 Self {
220 name: it.name,
221 hash: it.hash,
222 imports: it.imports,
223 exports: it.exports,
224 start_function: it.start_function,
225 table_initializers: it.table_initializers,
226 passive_elements: it.passive_elements.into_iter().collect(),
227 passive_data: it.passive_data.into_iter().collect(),
228 global_initializers: it.global_initializers,
229 function_names: it.function_names.into_iter().collect(),
230 signatures: it.signatures,
231 functions: it.functions,
232 tables: it.tables,
233 memories: it.memories,
234 globals: it.globals,
235 custom_sections: it.custom_sections,
236 custom_sections_data: it.custom_sections_data,
237 num_imported_functions: it.num_imported_functions,
238 num_imported_tables: it.num_imported_tables,
239 num_imported_memories: it.num_imported_memories,
240 num_imported_globals: it.num_imported_globals,
241 }
242 }
243}
244
245impl From<ArchivableModuleInfo> for ModuleInfo {
246 fn from(it: ArchivableModuleInfo) -> Self {
247 Self {
248 id: Default::default(),
249 name: it.name,
250 hash: it.hash,
251 imports: it.imports,
252 exports: it.exports,
253 start_function: it.start_function,
254 table_initializers: it.table_initializers,
255 passive_elements: it.passive_elements.into_iter().collect(),
256 passive_data: it.passive_data.into_iter().collect(),
257 global_initializers: it.global_initializers,
258 function_names: it.function_names.into_iter().collect(),
259 signatures: it.signatures,
260 functions: it.functions,
261 tables: it.tables,
262 memories: it.memories,
263 globals: it.globals,
264 custom_sections: it.custom_sections,
265 custom_sections_data: it.custom_sections_data,
266 num_imported_functions: it.num_imported_functions,
267 num_imported_tables: it.num_imported_tables,
268 num_imported_memories: it.num_imported_memories,
269 num_imported_globals: it.num_imported_globals,
270 }
271 }
272}
273
274impl From<&ModuleInfo> for ArchivableModuleInfo {
275 fn from(it: &ModuleInfo) -> Self {
276 Self::from(it.clone())
277 }
278}
279
280impl Archive for ModuleInfo {
281 type Archived = <ArchivableModuleInfo as Archive>::Archived;
282 type Resolver = <ArchivableModuleInfo as Archive>::Resolver;
283
284 unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) {
285 ArchivableModuleInfo::from(self).resolve(pos, resolver, out)
286 }
287}
288
289impl<S: Serializer + SharedSerializeRegistry + ScratchSpace + ?Sized> RkyvSerialize<S>
290 for ModuleInfo
291{
292 fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
293 ArchivableModuleInfo::from(self).serialize(serializer)
294 }
295}
296
297impl<D: Fallible + ?Sized + SharedDeserializeRegistry> RkyvDeserialize<ModuleInfo, D>
298 for Archived<ModuleInfo>
299{
300 fn deserialize(&self, deserializer: &mut D) -> Result<ModuleInfo, D::Error> {
301 let r: ArchivableModuleInfo =
302 RkyvDeserialize::<ArchivableModuleInfo, D>::deserialize(self, deserializer)?;
303 Ok(ModuleInfo::from(r))
304 }
305}
306
307impl PartialEq for ModuleInfo {
309 fn eq(&self, other: &Self) -> bool {
310 self.name == other.name
311 && self.imports == other.imports
312 && self.exports == other.exports
313 && self.start_function == other.start_function
314 && self.table_initializers == other.table_initializers
315 && self.passive_elements == other.passive_elements
316 && self.passive_data == other.passive_data
317 && self.global_initializers == other.global_initializers
318 && self.function_names == other.function_names
319 && self.signatures == other.signatures
320 && self.functions == other.functions
321 && self.tables == other.tables
322 && self.memories == other.memories
323 && self.globals == other.globals
324 && self.custom_sections == other.custom_sections
325 && self.custom_sections_data == other.custom_sections_data
326 && self.num_imported_functions == other.num_imported_functions
327 && self.num_imported_tables == other.num_imported_tables
328 && self.num_imported_memories == other.num_imported_memories
329 && self.num_imported_globals == other.num_imported_globals
330 }
331}
332
333impl Eq for ModuleInfo {}
334
335impl ModuleInfo {
336 pub fn new() -> Self {
338 Default::default()
339 }
340
341 pub fn hash(&self) -> Option<ModuleHash> {
343 self.hash
344 }
345
346 pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
348 self.passive_elements.get(&index).map(|es| &**es)
349 }
350
351 pub fn exported_signatures(&self) -> Vec<FunctionType> {
353 self.exports
354 .iter()
355 .filter_map(|(_name, export_index)| match export_index {
356 ExportIndex::Function(i) => {
357 let signature = self.functions.get(*i).unwrap();
358 let func_type = self.signatures.get(*signature).unwrap();
359 Some(func_type.clone())
360 }
361 _ => None,
362 })
363 .collect::<Vec<FunctionType>>()
364 }
365
366 pub fn exports(&'_ self) -> ExportsIterator<impl Iterator<Item = ExportType> + '_> {
368 let iter = self.exports.iter().map(move |(name, export_index)| {
369 let extern_type = match export_index {
370 ExportIndex::Function(i) => {
371 let signature = self.functions.get(*i).unwrap();
372 let func_type = self.signatures.get(*signature).unwrap();
373 ExternType::Function(func_type.clone())
374 }
375 ExportIndex::Table(i) => {
376 let table_type = self.tables.get(*i).unwrap();
377 ExternType::Table(*table_type)
378 }
379 ExportIndex::Memory(i) => {
380 let memory_type = self.memories.get(*i).unwrap();
381 ExternType::Memory(*memory_type)
382 }
383 ExportIndex::Global(i) => {
384 let global_type = self.globals.get(*i).unwrap();
385 ExternType::Global(*global_type)
386 }
387 };
388 ExportType::new(name, extern_type)
389 });
390 ExportsIterator::new(iter, self.exports.len())
391 }
392
393 pub fn imports(&'_ self) -> ImportsIterator<impl Iterator<Item = ImportType> + '_> {
395 let iter =
396 self.imports
397 .iter()
398 .map(move |(ImportKey { module, field, .. }, import_index)| {
399 let extern_type = match import_index {
400 ImportIndex::Function(i) => {
401 let signature = self.functions.get(*i).unwrap();
402 let func_type = self.signatures.get(*signature).unwrap();
403 ExternType::Function(func_type.clone())
404 }
405 ImportIndex::Table(i) => {
406 let table_type = self.tables.get(*i).unwrap();
407 ExternType::Table(*table_type)
408 }
409 ImportIndex::Memory(i) => {
410 let memory_type = self.memories.get(*i).unwrap();
411 ExternType::Memory(*memory_type)
412 }
413 ImportIndex::Global(i) => {
414 let global_type = self.globals.get(*i).unwrap();
415 ExternType::Global(*global_type)
416 }
417 };
418 ImportType::new(module, field, extern_type)
419 });
420 ImportsIterator::new(iter, self.imports.len())
421 }
422
423 pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Box<[u8]>> + 'a {
425 self.custom_sections
426 .iter()
427 .filter_map(move |(section_name, section_index)| {
428 if name != section_name {
429 return None;
430 }
431 Some(self.custom_sections_data[*section_index].clone())
432 })
433 }
434
435 pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
437 FunctionIndex::new(self.num_imported_functions + local_func.index())
438 }
439
440 pub fn local_func_index(&self, func: FunctionIndex) -> Option<LocalFunctionIndex> {
443 func.index()
444 .checked_sub(self.num_imported_functions)
445 .map(LocalFunctionIndex::new)
446 }
447
448 pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
450 index.index() < self.num_imported_functions
451 }
452
453 pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
455 TableIndex::new(self.num_imported_tables + local_table.index())
456 }
457
458 pub fn local_table_index(&self, table: TableIndex) -> Option<LocalTableIndex> {
461 table
462 .index()
463 .checked_sub(self.num_imported_tables)
464 .map(LocalTableIndex::new)
465 }
466
467 pub fn is_imported_table(&self, index: TableIndex) -> bool {
469 index.index() < self.num_imported_tables
470 }
471
472 pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
474 MemoryIndex::new(self.num_imported_memories + local_memory.index())
475 }
476
477 pub fn local_memory_index(&self, memory: MemoryIndex) -> Option<LocalMemoryIndex> {
480 memory
481 .index()
482 .checked_sub(self.num_imported_memories)
483 .map(LocalMemoryIndex::new)
484 }
485
486 pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
488 index.index() < self.num_imported_memories
489 }
490
491 pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
493 GlobalIndex::new(self.num_imported_globals + local_global.index())
494 }
495
496 pub fn local_global_index(&self, global: GlobalIndex) -> Option<LocalGlobalIndex> {
499 global
500 .index()
501 .checked_sub(self.num_imported_globals)
502 .map(LocalGlobalIndex::new)
503 }
504
505 pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
507 index.index() < self.num_imported_globals
508 }
509
510 pub fn name(&self) -> String {
512 match self.name {
513 Some(ref name) => name.to_string(),
514 None => "<module>".to_string(),
515 }
516 }
517
518 pub fn imported_function_types(&'_ self) -> impl Iterator<Item = FunctionType> + '_ {
520 self.functions
521 .values()
522 .take(self.num_imported_functions)
523 .map(move |sig_index| self.signatures[*sig_index].clone())
524 }
525}
526
527impl fmt::Display for ModuleInfo {
528 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529 write!(f, "{}", self.name())
530 }
531}
532
533pub struct ExportsIterator<I: Iterator<Item = ExportType> + Sized> {
539 iter: I,
540 size: usize,
541}
542
543impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
544 pub fn new(iter: I, size: usize) -> Self {
546 Self { iter, size }
547 }
548}
549
550impl<I: Iterator<Item = ExportType> + Sized> ExactSizeIterator for ExportsIterator<I> {
551 fn len(&self) -> usize {
553 self.size
554 }
555}
556
557impl<I: Iterator<Item = ExportType> + Sized> ExportsIterator<I> {
558 pub fn functions(self) -> impl Iterator<Item = ExportType<FunctionType>> + Sized {
560 self.iter.filter_map(|extern_| match extern_.ty() {
561 ExternType::Function(ty) => Some(ExportType::new(extern_.name(), ty.clone())),
562 _ => None,
563 })
564 }
565 pub fn memories(self) -> impl Iterator<Item = ExportType<MemoryType>> + Sized {
567 self.iter.filter_map(|extern_| match extern_.ty() {
568 ExternType::Memory(ty) => Some(ExportType::new(extern_.name(), *ty)),
569 _ => None,
570 })
571 }
572 pub fn tables(self) -> impl Iterator<Item = ExportType<TableType>> + Sized {
574 self.iter.filter_map(|extern_| match extern_.ty() {
575 ExternType::Table(ty) => Some(ExportType::new(extern_.name(), *ty)),
576 _ => None,
577 })
578 }
579 pub fn globals(self) -> impl Iterator<Item = ExportType<GlobalType>> + Sized {
581 self.iter.filter_map(|extern_| match extern_.ty() {
582 ExternType::Global(ty) => Some(ExportType::new(extern_.name(), *ty)),
583 _ => None,
584 })
585 }
586}
587
588impl<I: Iterator<Item = ExportType> + Sized> Iterator for ExportsIterator<I> {
589 type Item = ExportType;
590 fn next(&mut self) -> Option<Self::Item> {
591 self.iter.next()
592 }
593}
594
595pub struct ImportsIterator<I: Iterator<Item = ImportType> + Sized> {
598 iter: I,
599 size: usize,
600}
601
602impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
603 pub fn new(iter: I, size: usize) -> Self {
605 Self { iter, size }
606 }
607}
608
609impl<I: Iterator<Item = ImportType> + Sized> ExactSizeIterator for ImportsIterator<I> {
610 fn len(&self) -> usize {
612 self.size
613 }
614}
615
616impl<I: Iterator<Item = ImportType> + Sized> ImportsIterator<I> {
617 pub fn functions(self) -> impl Iterator<Item = ImportType<FunctionType>> + Sized {
619 self.iter.filter_map(|extern_| match extern_.ty() {
620 ExternType::Function(ty) => Some(ImportType::new(
621 extern_.module(),
622 extern_.name(),
623 ty.clone(),
624 )),
625 _ => None,
626 })
627 }
628 pub fn memories(self) -> impl Iterator<Item = ImportType<MemoryType>> + Sized {
630 self.iter.filter_map(|extern_| match extern_.ty() {
631 ExternType::Memory(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
632 _ => None,
633 })
634 }
635 pub fn tables(self) -> impl Iterator<Item = ImportType<TableType>> + Sized {
637 self.iter.filter_map(|extern_| match extern_.ty() {
638 ExternType::Table(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
639 _ => None,
640 })
641 }
642 pub fn globals(self) -> impl Iterator<Item = ImportType<GlobalType>> + Sized {
644 self.iter.filter_map(|extern_| match extern_.ty() {
645 ExternType::Global(ty) => Some(ImportType::new(extern_.module(), extern_.name(), *ty)),
646 _ => None,
647 })
648 }
649}
650
651impl<I: Iterator<Item = ImportType> + Sized> Iterator for ImportsIterator<I> {
652 type Item = ImportType;
653 fn next(&mut self) -> Option<Self::Item> {
654 self.iter.next()
655 }
656}