blob: 5bf3701035c3c14b4a6c3f460e338de7dfc10453 [file] [log] [blame]
use std::prelude::v1::*;
use std::io::{Read, Write};
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 enum NameSection {
/// Module name section.
Module(ModuleNameSection),
/// Function name section.
Function(FunctionNameSection),
/// Local name section.
Local(LocalNameSection),
/// Name section is unparsed.
Unparsed {
/// The numeric identifier for this name section type.
name_type: u8,
/// The contents of this name section, unparsed.
name_payload: Vec<u8>,
},
}
impl NameSection {
/// Deserialize a name section.
pub fn deserialize<R: Read>(
module: &Module,
rdr: &mut R,
) -> Result<NameSection, Error> {
let name_type: u8 = VarUint7::deserialize(rdr)?.into();
let name_payload_len: u32 = VarUint32::deserialize(rdr)?.into();
let name_section = match name_type {
NAME_TYPE_MODULE => NameSection::Module(ModuleNameSection::deserialize(rdr)?),
NAME_TYPE_FUNCTION => NameSection::Function(FunctionNameSection::deserialize(module, rdr)?),
NAME_TYPE_LOCAL => NameSection::Local(LocalNameSection::deserialize(module, rdr)?),
_ => {
let mut name_payload = vec![0u8; name_payload_len as usize];
rdr.read_exact(&mut name_payload)?;
NameSection::Unparsed {
name_type,
name_payload,
}
}
};
Ok(name_section)
}
}
impl Serialize for NameSection {
type Error = Error;
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
let (name_type, name_payload) = match self {
NameSection::Module(mod_name) => {
let mut buffer = vec![];
mod_name.serialize(&mut buffer)?;
(NAME_TYPE_MODULE, buffer)
}
NameSection::Function(fn_names) => {
let mut buffer = vec![];
fn_names.serialize(&mut buffer)?;
(NAME_TYPE_FUNCTION, buffer)
}
NameSection::Local(local_names) => {
let mut buffer = vec![];
local_names.serialize(&mut buffer)?;
(NAME_TYPE_LOCAL, buffer)
}
NameSection::Unparsed {
name_type,
name_payload,
} => (name_type, name_payload),
};
VarUint7::from(name_type).serialize(wtr)?;
VarUint32::from(name_payload.len()).serialize(wtr)?;
wtr.write_all(&name_payload)?;
Ok(())
}
}
/// The name of this module.
#[derive(Clone, Debug, PartialEq)]
pub struct ModuleNameSection {
name: String,
}
impl ModuleNameSection {
/// Create a new module name section with the specified name.
pub fn new<S: Into<String>>(name: S) -> ModuleNameSection {
ModuleNameSection { 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 ModuleNameSection {
type Error = Error;
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
self.name.serialize(wtr)
}
}
impl Deserialize for ModuleNameSection {
type Error = Error;
fn deserialize<R: Read>(rdr: &mut R) -> Result<ModuleNameSection, Error> {
let name = String::deserialize(rdr)?;
Ok(ModuleNameSection { name })
}
}
/// The names of the functions in this module.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct FunctionNameSection {
names: NameMap,
}
impl FunctionNameSection {
/// 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<R: Read>(
module: &Module,
rdr: &mut R,
) -> Result<FunctionNameSection, Error> {
let names = IndexMap::deserialize(module.functions_space(), rdr)?;
Ok(FunctionNameSection { names })
}
}
impl Serialize for FunctionNameSection {
type Error = Error;
fn serialize<W: Write>(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 LocalNameSection {
local_names: IndexMap<NameMap>,
}
impl LocalNameSection {
/// A map from function indices to a map from variables indices to names.
pub fn local_names(&self) -> &IndexMap<NameMap> {
&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<NameMap> {
&mut self.local_names
}
/// Deserialize names, making sure that all names correspond to local
/// variables.
pub fn deserialize<R: Read>(
module: &Module,
rdr: &mut R,
) -> Result<LocalNameSection, Error> {
let funcs = module.function_section().ok_or_else(|| {
Error::Other("cannot deserialize local names without a function section")
})?;
let max_entry_space = funcs.entries().len();
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(LocalNameSection { local_names })
}}
impl Serialize for LocalNameSection {
type Error = Error;
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
self.local_names.serialize(wtr)
}
}
/// A map from indices to names.
pub type NameMap = IndexMap<String>;
#[cfg(test)]
mod tests {
use super::*;
// A helper funtion for the tests. Serialize a section, deserialize it,
// and make sure it matches the original.
fn serialize_test(original: NameSection) -> Vec<u8> {
let mut buffer = vec![];
original
.serialize(&mut buffer)
.expect("serialize error");
buffer
}
#[test]
fn serialize_module_name() {
let original = NameSection::Module(ModuleNameSection::new("my_mod"));
serialize_test(original.clone());
}
#[test]
fn serialize_function_names() {
let mut sect = FunctionNameSection::default();
sect.names_mut().insert(0, "hello_world".to_string());
serialize_test(NameSection::Function(sect));
}
#[test]
fn serialize_local_names() {
let mut sect = LocalNameSection::default();
let mut locals = NameMap::default();
locals.insert(0, "msg".to_string());
sect.local_names_mut().insert(0, locals);
serialize_test(NameSection::Local(sect));
}
#[test]
fn serialize_and_deserialize_unparsed() {
let original = NameSection::Unparsed {
// A made-up name section type which is unlikely to be allocated
// soon, in order to allow us to test `Unparsed`.
name_type: 120,
name_payload: vec![0u8, 1, 2],
};
serialize_test(original.clone());
}
}