swasm_utils/
runtime_type.rs

1use swasm::{elements, builder};
2use self::elements::{ Module, GlobalEntry, External, ExportEntry, GlobalType, ValueType, InitExpr, Instruction, Internal };
3use byteorder::{ LittleEndian, ByteOrder };
4
5pub fn inject_runtime_type(module: Module, runtime_type: [u8; 4], runtime_version: u32) -> Module {
6	let runtime_type: u32 = LittleEndian::read_u32(&runtime_type);
7	let globals_count: u32 = match module.global_section() {
8		Some(ref section) => section.entries().len() as u32,
9		None => 0
10	};
11	let imported_globals_count: u32 = match module.import_section() {
12		Some(ref section) => section.entries().iter().filter(|e| match *e.external() {
13			External::Global(ref _a) => true,
14			_ => false
15		}).count() as u32,
16		None => 0
17	};
18	let total_globals_count: u32 = globals_count + imported_globals_count;
19
20	builder::from_module(module)
21		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Instruction::I32Const(runtime_type as i32), Instruction::End])))
22		.with_export(ExportEntry::new("RUNTIME_TYPE".into(), Internal::Global(total_globals_count)))
23		.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Instruction::I32Const(runtime_version as i32), Instruction::End])))
24		.with_export(ExportEntry::new("RUNTIME_VERSION".into(), Internal::Global(total_globals_count + 1)))
25	.build()
26}
27
28#[cfg(test)]
29mod tests {
30	use super::*;
31	#[test]
32	fn it_injects() {
33		let mut module = builder::module()
34			.with_global(GlobalEntry::new(GlobalType::new(ValueType::I32, false), InitExpr::new(vec![Instruction::I32Const(42 as i32)])))
35		.build();
36		let mut runtime_type: [u8; 4] = Default::default();
37		runtime_type.copy_from_slice(b"emcc");
38		module = inject_runtime_type(module, runtime_type, 1);
39		let global_section = module.global_section().expect("Global section expected");
40		assert_eq!(3, global_section.entries().len());
41		let export_section = module.export_section().expect("Export section expected");
42		assert!(export_section.entries().iter().find(|e| e.field() == "RUNTIME_TYPE" ).is_some());
43		assert!(export_section.entries().iter().find(|e| e.field() == "RUNTIME_VERSION" ).is_some());
44	}
45}