gparity_wasm/elements/
name_section.rs

1use crate::io;
2use alloc::string::String;
3
4use super::{
5	index_map::IndexMap, Deserialize, Error, Module, Serialize, Type, VarUint32, VarUint7,
6};
7
8const NAME_TYPE_MODULE: u8 = 0;
9const NAME_TYPE_FUNCTION: u8 = 1;
10const NAME_TYPE_LOCAL: u8 = 2;
11
12/// Debug name information.
13#[derive(Clone, Debug, PartialEq)]
14pub struct NameSection {
15	/// Module name subsection.
16	module: Option<ModuleNameSubsection>,
17
18	/// Function name subsection.
19	functions: Option<FunctionNameSubsection>,
20
21	/// Local name subsection.
22	locals: Option<LocalNameSubsection>,
23}
24
25impl NameSection {
26	/// Creates a new name section.
27	pub fn new(
28		module: Option<ModuleNameSubsection>,
29		functions: Option<FunctionNameSubsection>,
30		locals: Option<LocalNameSubsection>,
31	) -> Self {
32		Self { module, functions, locals }
33	}
34
35	/// Module name subsection of this section.
36	pub fn module(&self) -> Option<&ModuleNameSubsection> {
37		self.module.as_ref()
38	}
39
40	/// Module name subsection of this section (mutable).
41	pub fn module_mut(&mut self) -> &mut Option<ModuleNameSubsection> {
42		&mut self.module
43	}
44
45	/// Functions name subsection of this section.
46	pub fn functions(&self) -> Option<&FunctionNameSubsection> {
47		self.functions.as_ref()
48	}
49
50	/// Functions name subsection of this section (mutable).
51	pub fn functions_mut(&mut self) -> &mut Option<FunctionNameSubsection> {
52		&mut self.functions
53	}
54
55	/// Local name subsection of this section.
56	pub fn locals(&self) -> Option<&LocalNameSubsection> {
57		self.locals.as_ref()
58	}
59
60	/// Local name subsection of this section (mutable).
61	pub fn locals_mut(&mut self) -> &mut Option<LocalNameSubsection> {
62		&mut self.locals
63	}
64}
65
66impl NameSection {
67	/// Deserialize a name section.
68	pub fn deserialize<R: io::Read>(module: &Module, rdr: &mut R) -> Result<Self, Error> {
69		let mut module_name: Option<ModuleNameSubsection> = None;
70		let mut function_names: Option<FunctionNameSubsection> = None;
71		let mut local_names: Option<LocalNameSubsection> = None;
72
73		while let Ok(raw_subsection_type) = VarUint7::deserialize(rdr) {
74			let subsection_type = raw_subsection_type.into();
75			// deserialize the section size
76			VarUint32::deserialize(rdr)?;
77
78			match subsection_type {
79				NAME_TYPE_MODULE => {
80					if module_name.is_some() {
81						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION))
82					}
83					module_name = Some(ModuleNameSubsection::deserialize(rdr)?);
84				},
85
86				NAME_TYPE_FUNCTION => {
87					if function_names.is_some() {
88						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION))
89					}
90					function_names = Some(FunctionNameSubsection::deserialize(module, rdr)?);
91				},
92
93				NAME_TYPE_LOCAL => {
94					if local_names.is_some() {
95						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_LOCAL))
96					}
97					local_names = Some(LocalNameSubsection::deserialize(module, rdr)?);
98				},
99
100				_ => return Err(Error::UnknownNameSubsectionType(subsection_type)),
101			};
102		}
103
104		Ok(Self { module: module_name, functions: function_names, locals: local_names })
105	}
106}
107
108impl Serialize for NameSection {
109	type Error = Error;
110
111	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
112		fn serialize_subsection<W: io::Write>(
113			wtr: &mut W,
114			name_type: u8,
115			name_payload: &[u8],
116		) -> Result<(), Error> {
117			VarUint7::from(name_type).serialize(wtr)?;
118			VarUint32::from(name_payload.len()).serialize(wtr)?;
119			wtr.write(name_payload).map_err(Into::into)
120		}
121
122		if let Some(module_name_subsection) = self.module {
123			let mut buffer = vec![];
124			module_name_subsection.serialize(&mut buffer)?;
125			serialize_subsection(wtr, NAME_TYPE_MODULE, &buffer)?;
126		}
127
128		if let Some(function_name_subsection) = self.functions {
129			let mut buffer = vec![];
130			function_name_subsection.serialize(&mut buffer)?;
131			serialize_subsection(wtr, NAME_TYPE_FUNCTION, &buffer)?;
132		}
133
134		if let Some(local_name_subsection) = self.locals {
135			let mut buffer = vec![];
136			local_name_subsection.serialize(&mut buffer)?;
137			serialize_subsection(wtr, NAME_TYPE_LOCAL, &buffer)?;
138		}
139
140		Ok(())
141	}
142}
143
144/// The name of this module.
145#[derive(Clone, Debug, PartialEq)]
146pub struct ModuleNameSubsection {
147	name: String,
148}
149
150impl ModuleNameSubsection {
151	/// Create a new module name section with the specified name.
152	pub fn new<S: Into<String>>(name: S) -> ModuleNameSubsection {
153		ModuleNameSubsection { name: name.into() }
154	}
155
156	/// The name of this module.
157	pub fn name(&self) -> &str {
158		&self.name
159	}
160
161	/// The name of this module (mutable).
162	pub fn name_mut(&mut self) -> &mut String {
163		&mut self.name
164	}
165}
166
167impl Serialize for ModuleNameSubsection {
168	type Error = Error;
169
170	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
171		self.name.serialize(wtr)
172	}
173}
174
175impl Deserialize for ModuleNameSubsection {
176	type Error = Error;
177
178	fn deserialize<R: io::Read>(rdr: &mut R) -> Result<ModuleNameSubsection, Error> {
179		let name = String::deserialize(rdr)?;
180		Ok(ModuleNameSubsection { name })
181	}
182}
183
184/// The names of the functions in this module.
185#[derive(Clone, Debug, Default, PartialEq)]
186pub struct FunctionNameSubsection {
187	names: NameMap,
188}
189
190impl FunctionNameSubsection {
191	/// A map from function indices to names.
192	pub fn names(&self) -> &NameMap {
193		&self.names
194	}
195
196	/// A map from function indices to names (mutable).
197	pub fn names_mut(&mut self) -> &mut NameMap {
198		&mut self.names
199	}
200
201	/// Deserialize names, making sure that all names correspond to functions.
202	pub fn deserialize<R: io::Read>(
203		module: &Module,
204		rdr: &mut R,
205	) -> Result<FunctionNameSubsection, Error> {
206		let names = IndexMap::deserialize(module.functions_space(), rdr)?;
207		Ok(FunctionNameSubsection { names })
208	}
209}
210
211impl Serialize for FunctionNameSubsection {
212	type Error = Error;
213
214	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
215		self.names.serialize(wtr)
216	}
217}
218
219/// The names of the local variables in this module's functions.
220#[derive(Clone, Debug, Default, PartialEq)]
221pub struct LocalNameSubsection {
222	local_names: IndexMap<NameMap>,
223}
224
225impl LocalNameSubsection {
226	/// A map from function indices to a map from variables indices to names.
227	pub fn local_names(&self) -> &IndexMap<NameMap> {
228		&self.local_names
229	}
230
231	/// A map from function indices to a map from variables indices to names
232	/// (mutable).
233	pub fn local_names_mut(&mut self) -> &mut IndexMap<NameMap> {
234		&mut self.local_names
235	}
236
237	/// Deserialize names, making sure that all names correspond to local
238	/// variables.
239	pub fn deserialize<R: io::Read>(
240		module: &Module,
241		rdr: &mut R,
242	) -> Result<LocalNameSubsection, Error> {
243		let max_entry_space = module.functions_space();
244
245		let max_signature_args = module
246			.type_section()
247			.map(|ts| {
248				ts.types()
249					.iter()
250					.map(|x| {
251						let Type::Function(ref func) = *x;
252						func.params().len()
253					})
254					.max()
255					.unwrap_or(0)
256			})
257			.unwrap_or(0);
258
259		let max_locals = module
260			.code_section()
261			.map(|cs| {
262				cs.bodies()
263					.iter()
264					.map(|f| f.locals().iter().map(|l| l.count() as usize).sum())
265					.max()
266					.unwrap_or(0)
267			})
268			.unwrap_or(0);
269
270		let max_space = max_signature_args + max_locals;
271
272		let deserialize_locals = |_: u32, rdr: &mut R| IndexMap::deserialize(max_space, rdr);
273
274		let local_names = IndexMap::deserialize_with(max_entry_space, &deserialize_locals, rdr)?;
275		Ok(LocalNameSubsection { local_names })
276	}
277}
278
279impl Serialize for LocalNameSubsection {
280	type Error = Error;
281
282	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
283		self.local_names.serialize(wtr)
284	}
285}
286
287/// A map from indices to names.
288pub type NameMap = IndexMap<String>;
289
290#[cfg(test)]
291mod tests {
292	use super::*;
293
294	// A helper function for the tests. Serialize a section, deserialize it,
295	// and make sure it matches the original.
296	fn serialize_test(original: NameSection) -> Vec<u8> {
297		let mut buffer = vec![];
298		original.serialize(&mut buffer).expect("serialize error");
299		buffer
300		// todo: add deserialization to this test
301	}
302
303	#[test]
304	fn serialize_module_name() {
305		let module_name_subsection = ModuleNameSubsection::new("my_mod");
306		let original = NameSection::new(Some(module_name_subsection), None, None);
307		serialize_test(original);
308	}
309
310	#[test]
311	fn serialize_function_names() {
312		let mut function_name_subsection = FunctionNameSubsection::default();
313		function_name_subsection.names_mut().insert(0, "hello_world".to_string());
314		let name_section = NameSection::new(None, Some(function_name_subsection), None);
315		serialize_test(name_section);
316	}
317
318	#[test]
319	fn serialize_local_names() {
320		let mut local_name_subsection = LocalNameSubsection::default();
321		let mut locals = NameMap::default();
322		locals.insert(0, "msg".to_string());
323		local_name_subsection.local_names_mut().insert(0, locals);
324
325		let name_section = NameSection::new(None, None, Some(local_name_subsection));
326		serialize_test(name_section);
327	}
328
329	#[test]
330	fn serialize_all_subsections() {
331		let module_name_subsection = ModuleNameSubsection::new("ModuleNameSubsection");
332
333		let mut function_name_subsection = FunctionNameSubsection::default();
334		function_name_subsection.names_mut().insert(0, "foo".to_string());
335		function_name_subsection.names_mut().insert(1, "bar".to_string());
336
337		let mut local_name_subsection = LocalNameSubsection::default();
338		let mut locals = NameMap::default();
339		locals.insert(0, "msg1".to_string());
340		locals.insert(1, "msg2".to_string());
341		local_name_subsection.local_names_mut().insert(0, locals);
342
343		let name_section = NameSection::new(
344			Some(module_name_subsection),
345			Some(function_name_subsection),
346			Some(local_name_subsection),
347		);
348		serialize_test(name_section);
349	}
350
351	#[test]
352	fn deserialize_local_names() {
353		let module = super::super::deserialize_file("./res/cases/v1/names_with_imports.wasm")
354			.expect("Should be deserialized")
355			.parse_names()
356			.expect("Names to be parsed");
357
358		let name_section = module.names_section().expect("name_section should be present");
359		let local_names = name_section.locals().expect("local_name_section should be present");
360
361		let locals = local_names.local_names().get(0).expect("entry #0 should be present");
362		assert_eq!(locals.get(0).expect("entry #0 should be present"), "abc");
363
364		let locals = local_names.local_names().get(1).expect("entry #1 should be present");
365		assert_eq!(locals.get(0).expect("entry #0 should be present"), "def");
366	}
367}