use alloc::{string::String, vec::Vec}; use crate::io; use super::{Deserialize, Error, Module, Serialize, VarUint32, VarUint7, Type}; use super::index_map::IndexMap; const NAME_TYPE_MODULE: u8 = 0; const NAME_TYPE_FUNCTION: u8 = 1; const NAME_TYPE_LOCAL: u8 = 2; /// Debug name information. #[derive(Clone, Debug, PartialEq)] pub struct NameSection { /// Module name subsection. module: Option, /// Function name subsection. functions: Option, /// Local name subsection. locals: Option, } impl NameSection { /// Creates a new name section. pub fn new(module: Option, functions: Option, locals: Option) -> Self { Self { module, functions, locals, } } /// Module name subsection of this section. pub fn module(&self) -> Option<&ModuleNameSubsection> { self.module.as_ref() } /// Module name subsection of this section (mutable). pub fn module_mut(&mut self) -> &mut Option { &mut self.module } /// Functions name subsection of this section. pub fn functions(&self) -> Option<&FunctionNameSubsection> { self.functions.as_ref() } /// Functions name subsection of this section (mutable). pub fn functions_mut(&mut self) -> &mut Option { &mut self.functions } /// Local name subsection of this section. pub fn locals(&self) -> Option<&LocalNameSubsection> { self.locals.as_ref() } /// Local name subsection of this section (mutable). pub fn locals_mut(&mut self) -> &mut Option { &mut self.locals } } impl NameSection { /// Deserialize a name section. pub fn deserialize( module: &Module, rdr: &mut R, ) -> Result { let mut module_name: Option = None; let mut function_names: Option = None; let mut local_names: Option = None; loop { let subsection_type: u8 = match VarUint7::deserialize(rdr) { Ok(raw_subsection_type) => raw_subsection_type.into(), // todo: be more selective detecting no more subsection Err(_) => { break; }, }; // deserialize the section size VarUint32::deserialize(rdr)?; match subsection_type { NAME_TYPE_MODULE => { if let Some(_) = module_name { return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION)); } module_name = Some(ModuleNameSubsection::deserialize(rdr)?); }, NAME_TYPE_FUNCTION => { if let Some(_) = function_names { return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION)); } function_names = Some(FunctionNameSubsection::deserialize(module, rdr)?); }, NAME_TYPE_LOCAL => { if let Some(_) = local_names { return Err(Error::DuplicatedNameSubsections(NAME_TYPE_LOCAL)); } local_names = Some(LocalNameSubsection::deserialize(module, rdr)?); }, _ => return Err(Error::UnknownNameSubsectionType(subsection_type)) }; } Ok(Self { module: module_name, functions: function_names, locals: local_names, }) } } impl Serialize for NameSection { type Error = Error; fn serialize(self, wtr: &mut W) -> Result<(), Error> { fn serialize_subsection(wtr: &mut W, name_type: u8, name_payload: &Vec) -> Result<(), Error> { VarUint7::from(name_type).serialize(wtr)?; VarUint32::from(name_payload.len()).serialize(wtr)?; wtr.write(name_payload).map_err(Into::into) } if let Some(module_name_subsection) = self.module { let mut buffer = vec![]; module_name_subsection.serialize(&mut buffer)?; serialize_subsection(wtr, NAME_TYPE_MODULE, &buffer)?; } if let Some(function_name_subsection) = self.functions { let mut buffer = vec![]; function_name_subsection.serialize(&mut buffer)?; serialize_subsection(wtr, NAME_TYPE_FUNCTION, &buffer)?; } if let Some(local_name_subsection) = self.locals { let mut buffer = vec![]; local_name_subsection.serialize(&mut buffer)?; serialize_subsection(wtr, NAME_TYPE_LOCAL, &buffer)?; } Ok(()) } } /// The name of this module. #[derive(Clone, Debug, PartialEq)] pub struct ModuleNameSubsection { name: String, } impl ModuleNameSubsection { /// Create a new module name section with the specified name. pub fn new>(name: S) -> ModuleNameSubsection { ModuleNameSubsection { name: name.into() } } /// The name of this module. pub fn name(&self) -> &str { &self.name } /// The name of this module (mutable). pub fn name_mut(&mut self) -> &mut String { &mut self.name } } impl Serialize for ModuleNameSubsection { type Error = Error; fn serialize(self, wtr: &mut W) -> Result<(), Error> { self.name.serialize(wtr) } } impl Deserialize for ModuleNameSubsection { type Error = Error; fn deserialize(rdr: &mut R) -> Result { let name = String::deserialize(rdr)?; Ok(ModuleNameSubsection { name }) } } /// The names of the functions in this module. #[derive(Clone, Debug, Default, PartialEq)] pub struct FunctionNameSubsection { names: NameMap, } impl FunctionNameSubsection { /// A map from function indices to names. pub fn names(&self) -> &NameMap { &self.names } /// A map from function indices to names (mutable). pub fn names_mut(&mut self) -> &mut NameMap { &mut self.names } /// Deserialize names, making sure that all names correspond to functions. pub fn deserialize( module: &Module, rdr: &mut R, ) -> Result { let names = IndexMap::deserialize(module.functions_space(), rdr)?; Ok(FunctionNameSubsection { names }) } } impl Serialize for FunctionNameSubsection { type Error = Error; fn serialize(self, wtr: &mut W) -> Result<(), Error> { self.names.serialize(wtr) } } /// The names of the local variables in this module's functions. #[derive(Clone, Debug, Default, PartialEq)] pub struct LocalNameSubsection { local_names: IndexMap, } impl LocalNameSubsection { /// A map from function indices to a map from variables indices to names. pub fn local_names(&self) -> &IndexMap { &self.local_names } /// A map from function indices to a map from variables indices to names /// (mutable). pub fn local_names_mut(&mut self) -> &mut IndexMap { &mut self.local_names } /// Deserialize names, making sure that all names correspond to local /// variables. pub fn deserialize( module: &Module, rdr: &mut R, ) -> Result { let max_entry_space = module.functions_space(); let max_signature_args = module .type_section() .map(|ts| ts.types() .iter() .map(|x| { let Type::Function(ref func) = *x; func.params().len() }) .max() .unwrap_or(0)) .unwrap_or(0); let max_locals = module .code_section() .map(|cs| cs.bodies().iter().map(|f| f.locals().len()).max().unwrap_or(0)) .unwrap_or(0); let max_space = max_signature_args + max_locals; let deserialize_locals = |_: u32, rdr: &mut R| IndexMap::deserialize(max_space, rdr); let local_names = IndexMap::deserialize_with( max_entry_space, &deserialize_locals, rdr, )?; Ok(LocalNameSubsection { local_names }) }} impl Serialize for LocalNameSubsection { type Error = Error; fn serialize(self, wtr: &mut W) -> Result<(), Error> { self.local_names.serialize(wtr) } } /// A map from indices to names. pub type NameMap = IndexMap; #[cfg(test)] mod tests { use super::*; // A helper function for the tests. Serialize a section, deserialize it, // and make sure it matches the original. fn serialize_test(original: NameSection) -> Vec { let mut buffer = vec![]; original .serialize(&mut buffer) .expect("serialize error"); buffer // todo: add deserialization to this test } #[test] fn serialize_module_name() { let module_name_subsection = ModuleNameSubsection::new("my_mod"); let original = NameSection::new(Some(module_name_subsection), None, None); serialize_test(original.clone()); } #[test] fn serialize_function_names() { let mut function_name_subsection = FunctionNameSubsection::default(); function_name_subsection.names_mut().insert(0, "hello_world".to_string()); let name_section = NameSection::new(None, Some(function_name_subsection), None); serialize_test(name_section); } #[test] fn serialize_local_names() { let mut local_name_subsection = LocalNameSubsection::default(); let mut locals = NameMap::default(); locals.insert(0, "msg".to_string()); local_name_subsection.local_names_mut().insert(0, locals); let name_section = NameSection::new(None, None, Some(local_name_subsection)); serialize_test(name_section); } #[test] fn serialize_all_subsections() { let module_name_subsection = ModuleNameSubsection::new("ModuleNameSubsection"); let mut function_name_subsection = FunctionNameSubsection::default(); function_name_subsection.names_mut().insert(0, "foo".to_string()); function_name_subsection.names_mut().insert(1, "bar".to_string()); let mut local_name_subsection = LocalNameSubsection::default(); let mut locals = NameMap::default(); locals.insert(0, "msg1".to_string()); locals.insert(1, "msg2".to_string()); local_name_subsection.local_names_mut().insert(0, locals); let name_section = NameSection::new(Some(module_name_subsection), Some(function_name_subsection), Some(local_name_subsection)); serialize_test(name_section); } #[test] fn deserialize_local_names() { let module = super::super::deserialize_file("./res/cases/v1/names_with_imports.wasm") .expect("Should be deserialized") .parse_names() .expect("Names to be parsed"); let name_section = module.names_section().expect("name_section should be present"); let local_names = name_section.locals().expect("local_name_section should be present"); let locals = local_names.local_names().get(0).expect("entry #0 should be present"); assert_eq!( locals.get(0).expect("entry #0 should be present"), "abc" ); let locals = local_names.local_names().get(1).expect("entry #1 should be present"); assert_eq!( locals.get(0).expect("entry #0 should be present"), "def" ); } }