parity-wasm 0.28.0

WebAssembly binary format serialization/deserialization/interpreter
Documentation
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());
	}
}