1 use crate::map::IdHashMap;
2 use crate::{DataId, ElementId, Function, FunctionId, GlobalId, Result};
3 use crate::{LocalId, MemoryId, TableId, TypeId};
4 use anyhow::bail;
5 
6 /// Maps from old indices in the original Wasm binary to `walrus` IDs.
7 ///
8 /// This is intended to be used with `walrus::Module`s that were parsed from
9 /// some existing Wasm binary. `walrus::Module`s that are built up from scratch,
10 /// and not originally parsed from an existing Wasm binary, will have an empty
11 /// `IndicesToIds`.
12 ///
13 /// For example, this allows you to get the `walrus::FunctionId` of some Wasm
14 /// function when you have its old index in the original Wasm module.
15 ///
16 /// Any newly built or added things (functions, tables, types, etc) are not
17 /// associated with an old index (since they were not present in the original
18 /// Wasm binary).
19 #[derive(Debug, Default)]
20 pub struct IndicesToIds {
21     tables: Vec<TableId>,
22     types: Vec<TypeId>,
23     funcs: Vec<FunctionId>,
24     globals: Vec<GlobalId>,
25     memories: Vec<MemoryId>,
26     elements: Vec<ElementId>,
27     data: Vec<DataId>,
28     locals: IdHashMap<Function, Vec<LocalId>>,
29 }
30 
31 macro_rules! define_push_get {
32     ( $push:ident, $get:ident, $id_ty:ty, $member:ident ) => {
33         impl IndicesToIds {
34             /// Pushes a new local ID to map it to the next index internally
35             pub(crate) fn $push(&mut self, id: $id_ty) -> u32 {
36                 self.$member.push(id);
37                 (self.$member.len() - 1) as u32
38             }
39 
40             /// Gets the ID for a particular index.
41             ///
42             /// If the index did not exist in the original Wasm binary, an `Err`
43             /// is returned.
44             pub fn $get(&self, index: u32) -> Result<$id_ty> {
45                 match self.$member.get(index as usize) {
46                     Some(x) => Ok(*x),
47                     None => bail!(
48                         "index `{}` is out of bounds for {}",
49                         index,
50                         stringify!($member)
51                     ),
52                 }
53             }
54         }
55     };
56 }
57 
58 define_push_get!(push_table, get_table, TableId, tables);
59 define_push_get!(push_type, get_type, TypeId, types);
60 define_push_get!(push_func, get_func, FunctionId, funcs);
61 define_push_get!(push_global, get_global, GlobalId, globals);
62 define_push_get!(push_memory, get_memory, MemoryId, memories);
63 define_push_get!(push_element, get_element, ElementId, elements);
64 define_push_get!(push_data, get_data, DataId, data);
65 
66 impl IndicesToIds {
67     /// Pushes a new local ID to map it to the next index internally
push_local(&mut self, function: FunctionId, id: LocalId) -> u3268     pub(crate) fn push_local(&mut self, function: FunctionId, id: LocalId) -> u32 {
69         let list = self.locals.entry(function).or_insert(Vec::new());
70         list.push(id);
71         (list.len() as u32) - 1
72     }
73 
74     /// Gets the ID for a particular index
get_local(&self, function: FunctionId, index: u32) -> Result<LocalId>75     pub fn get_local(&self, function: FunctionId, index: u32) -> Result<LocalId> {
76         let ret = self
77             .locals
78             .get(&function)
79             .and_then(|list| list.get(index as usize));
80         match ret {
81             Some(x) => Ok(*x),
82             None => bail!("index `{}` is out of bounds for local", index,),
83         }
84     }
85 }
86