tetsy_wasm/elements/
name_section.rs

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