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