spaces to tabs

This commit is contained in:
NikVolf
2018-01-23 22:47:20 +03:00
parent bb24f2a11a
commit f915a89b9d
36 changed files with 5875 additions and 5876 deletions

View File

@ -11,37 +11,37 @@ use parity_wasm::elements;
fn main() { fn main() {
// Example binary accepts one parameter which is the output file // Example binary accepts one parameter which is the output file
// where generated wasm module will be written at the end of execution // where generated wasm module will be written at the end of execution
let args = env::args().collect::<Vec<_>>(); let args = env::args().collect::<Vec<_>>();
if args.len() != 2 { if args.len() != 2 {
println!("Usage: {} output_file.wasm", args[0]); println!("Usage: {} output_file.wasm", args[0]);
return; return;
} }
// Main entry for the builder api is the module function // Main entry for the builder api is the module function
// It returns empty module builder structure which can be further // It returns empty module builder structure which can be further
// appended with various wasm artefacts // appended with various wasm artefacts
let module = builder::module() let module = builder::module()
// Here we append function to the builder // Here we append function to the builder
// function() function returns a function builder attached // function() function returns a function builder attached
// to the module builder. // to the module builder.
.function() .function()
// We describe signature for the function via signature() // We describe signature for the function via signature()
// function. In our simple example it's just one input // function. In our simple example it's just one input
// argument of type 'i32' without return value // argument of type 'i32' without return value
.signature().with_param(elements::ValueType::I32).build() .signature().with_param(elements::ValueType::I32).build()
// body() without any further arguments means that the body // body() without any further arguments means that the body
// of the function will be empty // of the function will be empty
.body().build() .body().build()
// This is the end of the function builder. When `build()` is // This is the end of the function builder. When `build()` is
// invoked, function builder returns original module builder // invoked, function builder returns original module builder
// from which it was invoked // from which it was invoked
.build() .build()
// And finally we finish our module builder to produce actual // And finally we finish our module builder to produce actual
// wasm module. // wasm module.
.build(); .build();
// Module structure can be serialzed to produce a valid wasm file // Module structure can be serialzed to produce a valid wasm file
parity_wasm::serialize_to_file(&args[1], module).unwrap(); parity_wasm::serialize_to_file(&args[1], module).unwrap();
} }

View File

@ -7,40 +7,40 @@ use std::env;
fn main() { fn main() {
// Example executable takes one argument which must // Example executable takes one argument which must
// refernce the existing file with a valid wasm module // refernce the existing file with a valid wasm module
let args = env::args().collect::<Vec<_>>(); let args = env::args().collect::<Vec<_>>();
if args.len() != 2 { if args.len() != 2 {
println!("Usage: {} somefile.wasm", args[0]); println!("Usage: {} somefile.wasm", args[0]);
return; return;
} }
// Here we load module using dedicated for this purpose // Here we load module using dedicated for this purpose
// `deserialize_file` function (which works only with modules) // `deserialize_file` function (which works only with modules)
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module"); let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
// We query module for data section. Note that not every valid // We query module for data section. Note that not every valid
// wasm module must contain a data section. So in case the provided // wasm module must contain a data section. So in case the provided
// module does not contain data section, we panic with an error // module does not contain data section, we panic with an error
let data_section = module.data_section().expect("no data section in module"); let data_section = module.data_section().expect("no data section in module");
// Printing the total count of data segments // Printing the total count of data segments
println!("Data segments: {}", data_section.entries().len()); println!("Data segments: {}", data_section.entries().len());
let mut index = 0; let mut index = 0;
for entry in data_section.entries() { for entry in data_section.entries() {
// Printing the details info of each data segment // Printing the details info of each data segment
// see `elements::DataSegment` for more properties // see `elements::DataSegment` for more properties
// you can query // you can query
println!(" Entry #{}", index); println!(" Entry #{}", index);
// This shows the initialization member of data segment // This shows the initialization member of data segment
// (expression which must resolve in the linear memory location). // (expression which must resolve in the linear memory location).
println!(" init: {}", entry.offset().code()[0]); println!(" init: {}", entry.offset().code()[0]);
// This shows the total length of the data segment in bytes. // This shows the total length of the data segment in bytes.
println!(" size: {}", entry.value().len()); println!(" size: {}", entry.value().len());
index += 1; index += 1;
} }
} }

View File

@ -10,74 +10,74 @@ use parity_wasm::elements::{Internal, External, Type, FunctionType, Module};
// Auxillary function to resolve function type (signature) given it's callable index // Auxillary function to resolve function type (signature) given it's callable index
fn type_by_index(module: &Module, index: usize) -> FunctionType { fn type_by_index(module: &Module, index: usize) -> FunctionType {
// Demand that function and type section exist. Otherwise, fail with a // Demand that function and type section exist. Otherwise, fail with a
// corresponding error. // corresponding error.
let function_section = module.function_section().expect("No function section found"); let function_section = module.function_section().expect("No function section found");
let type_section = module.type_section().expect("No type section found"); let type_section = module.type_section().expect("No type section found");
// This counts the number of _function_ imports listed by the module, excluding // This counts the number of _function_ imports listed by the module, excluding
// the globals, since indexing for actual functions for `call` and `export` purposes // the globals, since indexing for actual functions for `call` and `export` purposes
// includes both imported and own functions. So we actualy need the imported function count // includes both imported and own functions. So we actualy need the imported function count
// to resolve actual index of the given function in own functions list. // to resolve actual index of the given function in own functions list.
let import_section_len: usize = match module.import_section() { let import_section_len: usize = match module.import_section() {
Some(import) => Some(import) =>
import.entries().iter().filter(|entry| match entry.external() { import.entries().iter().filter(|entry| match entry.external() {
&External::Function(_) => true, &External::Function(_) => true,
_ => false, _ => false,
}).count(), }).count(),
None => 0, None => 0,
}; };
// Substract the value queried in the previous step from the provided index // Substract the value queried in the previous step from the provided index
// to get own function index from which we can query type next. // to get own function index from which we can query type next.
let function_index_in_section = index - import_section_len; let function_index_in_section = index - import_section_len;
// Query the own function given we have it's index // Query the own function given we have it's index
let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize; let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize;
// Finally, return function type (signature) // Finally, return function type (signature)
match type_section.types()[func_type_ref] { match type_section.types()[func_type_ref] {
Type::Function(ref func_type) => func_type.clone(), Type::Function(ref func_type) => func_type.clone(),
} }
} }
fn main() { fn main() {
// Example executable takes one argument which must // Example executable takes one argument which must
// refernce the existing file with a valid wasm module // refernce the existing file with a valid wasm module
let args: Vec<_> = args().collect(); let args: Vec<_> = args().collect();
if args.len() < 2 { if args.len() < 2 {
println!("Prints export function names with and their types"); println!("Prints export function names with and their types");
println!("Usage: {} <wasm file>", args[0]); println!("Usage: {} <wasm file>", args[0]);
return; return;
} }
// Here we load module using dedicated for this purpose // Here we load module using dedicated for this purpose
// `deserialize_file` function (which works only with modules) // `deserialize_file` function (which works only with modules)
let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized"); let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized");
// Query the export section from the loaded module. Note that not every // Query the export section from the loaded module. Note that not every
// wasm module obliged to contain export section. So in case there is no // wasm module obliged to contain export section. So in case there is no
// any export section, we panic with the corresponding error. // any export section, we panic with the corresponding error.
let export_section = module.export_section().expect("No export section found"); let export_section = module.export_section().expect("No export section found");
// Process all exports, leaving only those which reference the internal function // Process all exports, leaving only those which reference the internal function
// of the wasm module // of the wasm module
let exports: Vec<String> = export_section.entries().iter() let exports: Vec<String> = export_section.entries().iter()
.filter_map(|entry| .filter_map(|entry|
// This is match on export variant, which can be function, global,table or memory // This is match on export variant, which can be function, global,table or memory
// We are interested only in functions for an example // We are interested only in functions for an example
match *entry.internal() { match *entry.internal() {
// Return function export name (return by field() function and it's index) // Return function export name (return by field() function and it's index)
Internal::Function(index) => Some((entry.field(), index as usize)), Internal::Function(index) => Some((entry.field(), index as usize)),
_ => None _ => None
}) })
// Another map to resolve function signature index given it's internal index and return // Another map to resolve function signature index given it's internal index and return
// the printable string of the export // the printable string of the export
.map(|(field, index)| format!("{:}: {:?}", field, type_by_index(&module, index).params())).collect(); .map(|(field, index)| format!("{:}: {:?}", field, type_by_index(&module, index).params())).collect();
// Print the result // Print the result
for export in exports { for export in exports {
println!("{:}", export); println!("{:}", export);
} }
} }

View File

@ -4,40 +4,40 @@ use std::env;
use parity_wasm::elements::Section; use parity_wasm::elements::Section;
fn main() { fn main() {
let args = env::args().collect::<Vec<_>>(); let args = env::args().collect::<Vec<_>>();
if args.len() != 2 { if args.len() != 2 {
println!("Usage: {} somefile.wasm", args[0]); println!("Usage: {} somefile.wasm", args[0]);
return; return;
} }
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module"); let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
println!("Module sections: {}", module.sections().len()); println!("Module sections: {}", module.sections().len());
for section in module.sections() { for section in module.sections() {
match *section { match *section {
Section::Import(ref import_section) => { Section::Import(ref import_section) => {
println!(" Imports: {}", import_section.entries().len()); println!(" Imports: {}", import_section.entries().len());
import_section.entries().iter().map(|e| println!(" {}.{}", e.module(), e.field())).count(); import_section.entries().iter().map(|e| println!(" {}.{}", e.module(), e.field())).count();
}, },
Section::Export(ref exports_section) => { Section::Export(ref exports_section) => {
println!(" Exports: {}", exports_section.entries().len()); println!(" Exports: {}", exports_section.entries().len());
exports_section.entries().iter().map(|e| println!(" {}", e.field())).count(); exports_section.entries().iter().map(|e| println!(" {}", e.field())).count();
}, },
Section::Function(ref function_section) => { Section::Function(ref function_section) => {
println!(" Functions: {}", function_section.entries().len()); println!(" Functions: {}", function_section.entries().len());
}, },
Section::Type(ref type_section) => { Section::Type(ref type_section) => {
println!(" Types: {}", type_section.types().len()); println!(" Types: {}", type_section.types().len());
}, },
Section::Global(ref globals_section) => { Section::Global(ref globals_section) => {
println!(" Globals: {}", globals_section.entries().len()); println!(" Globals: {}", globals_section.entries().len());
}, },
Section::Data(ref data_section) if data_section.entries().len() > 0 => { Section::Data(ref data_section) if data_section.entries().len() > 0 => {
let data = &data_section.entries()[0]; let data = &data_section.entries()[0];
println!(" Data size: {}", data.value().len()); println!(" Data size: {}", data.value().len());
}, },
_ => {}, _ => {},
} }
} }
} }

View File

@ -6,58 +6,58 @@ use parity_wasm::elements;
use parity_wasm::builder; use parity_wasm::builder;
pub fn inject_nop(opcodes: &mut elements::Opcodes) { pub fn inject_nop(opcodes: &mut elements::Opcodes) {
use parity_wasm::elements::Opcode::*; use parity_wasm::elements::Opcode::*;
let opcodes = opcodes.elements_mut(); let opcodes = opcodes.elements_mut();
let mut position = 0; let mut position = 0;
loop { loop {
let need_inject = match &opcodes[position] { let need_inject = match &opcodes[position] {
&Block(_) | &If(_) => true, &Block(_) | &If(_) => true,
_ => false, _ => false,
}; };
if need_inject { if need_inject {
opcodes.insert(position + 1, Nop); opcodes.insert(position + 1, Nop);
} }
position += 1; position += 1;
if position >= opcodes.len() { if position >= opcodes.len() {
break; break;
} }
} }
} }
fn main() { fn main() {
let args = env::args().collect::<Vec<_>>(); let args = env::args().collect::<Vec<_>>();
if args.len() != 3 { if args.len() != 3 {
println!("Usage: {} input_file.wasm output_file.wasm", args[0]); println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
return; return;
} }
let mut module = parity_wasm::deserialize_file(&args[1]).unwrap(); let mut module = parity_wasm::deserialize_file(&args[1]).unwrap();
for section in module.sections_mut() { for section in module.sections_mut() {
match section { match section {
&mut elements::Section::Code(ref mut code_section) => { &mut elements::Section::Code(ref mut code_section) => {
for ref mut func_body in code_section.bodies_mut() { for ref mut func_body in code_section.bodies_mut() {
inject_nop(func_body.code_mut()); inject_nop(func_body.code_mut());
} }
}, },
_ => { } _ => { }
} }
} }
let mut build = builder::from_module(module); let mut build = builder::from_module(module);
let import_sig = build.push_signature( let import_sig = build.push_signature(
builder::signature() builder::signature()
.param().i32() .param().i32()
.param().i32() .param().i32()
.return_type().i32() .return_type().i32()
.build_sig() .build_sig()
); );
let build = build.import() let build = build.import()
.module("env") .module("env")
.field("log") .field("log")
.external().func(import_sig) .external().func(import_sig)
.build(); .build();
parity_wasm::serialize_to_file(&args[2], build.build()).unwrap(); parity_wasm::serialize_to_file(&args[2], build.build()).unwrap();
} }

View File

@ -7,30 +7,30 @@ use std::env::args;
use parity_wasm::ModuleInstanceInterface; use parity_wasm::ModuleInstanceInterface;
fn main() { fn main() {
let args: Vec<_> = args().collect(); let args: Vec<_> = args().collect();
if args.len() != 3 { if args.len() != 3 {
println!("Usage: {} <wasm file> <arg>", args[0]); println!("Usage: {} <wasm file> <arg>", args[0]);
println!(" wasm file should contain exported `_call` function with single I32 argument"); println!(" wasm file should contain exported `_call` function with single I32 argument");
return; return;
} }
// Intrepreter initialization. // Intrepreter initialization.
let program = parity_wasm::ProgramInstance::new(); let program = parity_wasm::ProgramInstance::new();
// Here we load module using dedicated for this purpose // Here we load module using dedicated for this purpose
// `deserialize_file` function (which works only with modules) // `deserialize_file` function (which works only with modules)
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module"); let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
// Intialize deserialized module. It adds module into It expects 3 parameters: // Intialize deserialized module. It adds module into It expects 3 parameters:
// - a name for the module // - a name for the module
// - a module declaration // - a module declaration
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
let module = program.add_module("main", module, None).expect("Failed to initialize module"); let module = program.add_module("main", module, None).expect("Failed to initialize module");
// The argument should be parsable as a valid integer // The argument should be parsable as a valid integer
let argument: i32 = args[2].parse().expect("Integer argument required"); let argument: i32 = args[2].parse().expect("Integer argument required");
// "_call" export of function to be executed with an i32 argument and prints the result of execution // "_call" export of function to be executed with an i32 argument and prints the result of execution
println!("Result: {:?}", module.execute_export("_call", vec![parity_wasm::RuntimeValue::I32(argument)].into())); println!("Result: {:?}", module.execute_export("_call", vec![parity_wasm::RuntimeValue::I32(argument)].into()));
} }

View File

@ -5,80 +5,79 @@ use std::env::args;
use parity_wasm::{interpreter, ModuleInstanceInterface, RuntimeValue}; use parity_wasm::{interpreter, ModuleInstanceInterface, RuntimeValue};
use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType}; use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType};
fn main() { fn main() {
let args: Vec<_> = args().collect(); let args: Vec<_> = args().collect();
if args.len() < 3 { if args.len() < 3 {
println!("Usage: {} <wasm file> <exported func> [<arg>...]", args[0]); println!("Usage: {} <wasm file> <exported func> [<arg>...]", args[0]);
return; return;
} }
let func_name = &args[2]; let func_name = &args[2];
let (_, program_args) = args.split_at(3); let (_, program_args) = args.split_at(3);
// Intrepreter initialization. // Intrepreter initialization.
let program = parity_wasm::ProgramInstance::new(); let program = parity_wasm::ProgramInstance::new();
let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized"); let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized");
// Extracts call arguments from command-line arguments // Extracts call arguments from command-line arguments
let execution_params = { let execution_params = {
// Export section has an entry with a func_name with an index inside a module // Export section has an entry with a func_name with an index inside a module
let export_section = module.export_section().expect("No export section found"); let export_section = module.export_section().expect("No export section found");
// It's a section with function declarations (which are references to the type section entries) // It's a section with function declarations (which are references to the type section entries)
let function_section = module.function_section().expect("No function section found"); let function_section = module.function_section().expect("No function section found");
// Type section stores function types which are referenced by function_section entries // Type section stores function types which are referenced by function_section entries
let type_section = module.type_section().expect("No type section found"); let type_section = module.type_section().expect("No type section found");
// Given function name used to find export section entry which contains // Given function name used to find export section entry which contains
// an `internal` field which points to the index in the function index space // an `internal` field which points to the index in the function index space
let found_entry = export_section.entries().iter() let found_entry = export_section.entries().iter()
.find(|entry| func_name == entry.field()).expect(&format!("No export with name {} found", func_name)); .find(|entry| func_name == entry.field()).expect(&format!("No export with name {} found", func_name));
// Function index in the function index space (internally-defined + imported) // Function index in the function index space (internally-defined + imported)
let function_index: usize = match found_entry.internal() { let function_index: usize = match found_entry.internal() {
&Internal::Function(index) => index as usize, &Internal::Function(index) => index as usize,
_ => panic!("Founded export is not a function"), _ => panic!("Founded export is not a function"),
}; };
// We need to count import section entries (functions only!) to subtract it from function_index // We need to count import section entries (functions only!) to subtract it from function_index
// and obtain the index within the function section // and obtain the index within the function section
let import_section_len: usize = match module.import_section() { let import_section_len: usize = match module.import_section() {
Some(import) => Some(import) =>
import.entries().iter().filter(|entry| match entry.external() { import.entries().iter().filter(|entry| match entry.external() {
&External::Function(_) => true, &External::Function(_) => true,
_ => false, _ => false,
}).count(), }).count(),
None => 0, None => 0,
}; };
// Calculates a function index within module's function section // Calculates a function index within module's function section
let function_index_in_section = function_index - import_section_len; let function_index_in_section = function_index - import_section_len;
// Getting a type reference from a function section entry // Getting a type reference from a function section entry
let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize; let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize;
// Use the reference to get an actual function type // Use the reference to get an actual function type
let function_type: &FunctionType = match &type_section.types()[func_type_ref] { let function_type: &FunctionType = match &type_section.types()[func_type_ref] {
&Type::Function(ref func_type) => func_type, &Type::Function(ref func_type) => func_type,
}; };
// Parses arguments and constructs runtime values in correspondence of their types // Parses arguments and constructs runtime values in correspondence of their types
let args: Vec<RuntimeValue> = function_type.params().iter().enumerate().map(|(i, value)| match value { let args: Vec<RuntimeValue> = function_type.params().iter().enumerate().map(|(i, value)| match value {
&ValueType::I32 => RuntimeValue::I32(program_args[i].parse::<i32>().expect(&format!("Can't parse arg #{} as i32", program_args[i]))), &ValueType::I32 => RuntimeValue::I32(program_args[i].parse::<i32>().expect(&format!("Can't parse arg #{} as i32", program_args[i]))),
&ValueType::I64 => RuntimeValue::I64(program_args[i].parse::<i64>().expect(&format!("Can't parse arg #{} as i64", program_args[i]))), &ValueType::I64 => RuntimeValue::I64(program_args[i].parse::<i64>().expect(&format!("Can't parse arg #{} as i64", program_args[i]))),
&ValueType::F32 => RuntimeValue::F32(program_args[i].parse::<f32>().expect(&format!("Can't parse arg #{} as f32", program_args[i]))), &ValueType::F32 => RuntimeValue::F32(program_args[i].parse::<f32>().expect(&format!("Can't parse arg #{} as f32", program_args[i]))),
&ValueType::F64 => RuntimeValue::F64(program_args[i].parse::<f64>().expect(&format!("Can't parse arg #{} as f64", program_args[i]))), &ValueType::F64 => RuntimeValue::F64(program_args[i].parse::<f64>().expect(&format!("Can't parse arg #{} as f64", program_args[i]))),
}).collect(); }).collect();
interpreter::ExecutionParams::from(args) interpreter::ExecutionParams::from(args)
}; };
// Intialize deserialized module. It adds module into It expects 3 parameters: // Intialize deserialized module. It adds module into It expects 3 parameters:
// - a name for the module // - a name for the module
// - a module declaration // - a module declaration
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here // - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197 // This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
let module = program.add_module("main", module, None).expect("Failed to initialize module"); let module = program.add_module("main", module, None).expect("Failed to initialize module");
println!("Result: {:?}", module.execute_export(func_name, execution_params).expect("")); println!("Result: {:?}", module.execute_export(func_name, execution_params).expect(""));
} }

View File

@ -3,24 +3,24 @@ extern crate parity_wasm;
use std::env; use std::env;
fn main() { fn main() {
let args = env::args().collect::<Vec<_>>(); let args = env::args().collect::<Vec<_>>();
if args.len() != 3 { if args.len() != 3 {
println!("Usage: {} in.wasm out.wasm", args[0]); println!("Usage: {} in.wasm out.wasm", args[0]);
return; return;
} }
let module = match parity_wasm::deserialize_file(&args[1]) let module = match parity_wasm::deserialize_file(&args[1])
.expect("Failed to load module") .expect("Failed to load module")
.parse_names() .parse_names()
{ {
Ok(m) => m, Ok(m) => m,
Err((errors, m)) => { Err((errors, m)) => {
for (index, error) in errors.into_iter() { for (index, error) in errors.into_iter() {
println!("Custom section #{} parse error: {:?}", index, error); println!("Custom section #{} parse error: {:?}", index, error);
} }
m m
} }
}; };
parity_wasm::serialize_to_file(&args[2], module).expect("Failed to write module"); parity_wasm::serialize_to_file(&args[2], module).expect("Failed to write module");
} }

View File

@ -5,15 +5,15 @@ extern crate parity_wasm;
extern crate binaryen; extern crate binaryen;
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
let binaryen_module = binaryen::tools::translate_to_fuzz(data); let binaryen_module = binaryen::tools::translate_to_fuzz(data);
// enable binaryen's validation if in doubt. // enable binaryen's validation if in doubt.
// assert!(binaryen_module.is_valid()); // assert!(binaryen_module.is_valid());
let wasm = binaryen_module.write(); let wasm = binaryen_module.write();
let _module: parity_wasm::elements::Module = parity_wasm::deserialize_buffer(&wasm) let _module: parity_wasm::elements::Module = parity_wasm::deserialize_buffer(&wasm)
.expect( .expect(
"deserialize output of wasm-opt, indicating possible bug in deserializer", "deserialize output of wasm-opt, indicating possible bug in deserializer",
); );
}); });

View File

@ -1,16 +1,16 @@
macro_rules! run_test { macro_rules! run_test {
($label: expr, $test_name: ident, fail) => ( ($label: expr, $test_name: ident, fail) => (
#[test] #[test]
fn $test_name() { fn $test_name() {
::run::failing_spec($label) ::run::failing_spec($label)
} }
); );
($label: expr, $test_name: ident) => ( ($label: expr, $test_name: ident) => (
#[test] #[test]
fn $test_name() { fn $test_name() {
::run::spec($label) ::run::spec($label)
} }
); );
} }
run_test!("address-offset-range.fail", wasm_address_offset_range_fail, fail); run_test!("address-offset-range.fail", wasm_address_offset_range_fail, fail);

View File

@ -10,276 +10,276 @@ use serde_json;
use test; use test;
use parity_wasm::{self, elements, builder}; use parity_wasm::{self, elements, builder};
use parity_wasm::interpreter::{ use parity_wasm::interpreter::{
RuntimeValue, RuntimeValue,
ProgramInstance, ModuleInstance, ProgramInstance, ModuleInstance,
ItemIndex, ExportEntryType, ItemIndex, ExportEntryType,
Error as InterpreterError, Error as InterpreterError,
}; };
fn spec_test_module() -> elements::Module { fn spec_test_module() -> elements::Module {
builder::module() builder::module()
.function().signature().build().body().build().build() .function().signature().build().body().build().build()
.function().signature().param().i32().build().body().build().build() .function().signature().param().i32().build().body().build().build()
.function().signature().param().i64().build().body().build().build() .function().signature().param().i64().build().body().build().build()
.function().signature().param().f32().build().body().build().build() .function().signature().param().f32().build().body().build().build()
.function().signature().param().f64().build().body().build().build() .function().signature().param().f64().build().body().build().build()
.function().signature().param().i32().param().f32().build().body().build().build() .function().signature().param().i32().param().f32().build().body().build().build()
.function().signature().param().f64().param().f64().build().body().build().build() .function().signature().param().f64().param().f64().build().body().build().build()
.global().value_type().i32().init_expr(elements::Opcode::I32Const(666)).build() .global().value_type().i32().init_expr(elements::Opcode::I32Const(666)).build()
.with_table(elements::TableType::new(100, None)) .with_table(elements::TableType::new(100, None))
.memory().with_min(1).with_max(Some(2)).build() .memory().with_min(1).with_max(Some(2)).build()
.export().field("print").internal().func(0).build() .export().field("print").internal().func(0).build()
.export().field("print").internal().func(1).build() .export().field("print").internal().func(1).build()
.export().field("print").internal().func(2).build() .export().field("print").internal().func(2).build()
.export().field("print").internal().func(3).build() .export().field("print").internal().func(3).build()
.export().field("print").internal().func(4).build() .export().field("print").internal().func(4).build()
.export().field("print").internal().func(5).build() .export().field("print").internal().func(5).build()
.export().field("print").internal().func(6).build() .export().field("print").internal().func(6).build()
.export().field("global").internal().global(0).build() .export().field("global").internal().global(0).build()
.export().field("table").internal().table(0).build() .export().field("table").internal().table(0).build()
.export().field("memory").internal().memory(0).build() .export().field("memory").internal().memory(0).build()
.build() .build()
} }
fn load_module(base_dir: &str, path: &str, name: &Option<String>, program: &ProgramInstance) -> Arc<ModuleInstance> { fn load_module(base_dir: &str, path: &str, name: &Option<String>, program: &ProgramInstance) -> Arc<ModuleInstance> {
let module = try_deserialize(base_dir, path).expect(&format!("Wasm file {} failed to load", path)); let module = try_deserialize(base_dir, path).expect(&format!("Wasm file {} failed to load", path));
program.add_module("spectest", spec_test_module(), None).expect("Failed adding 'spectest' module"); program.add_module("spectest", spec_test_module(), None).expect("Failed adding 'spectest' module");
let module_name = name.as_ref().map(|s| s.as_ref()).unwrap_or("wasm_test").trim_left_matches('$'); let module_name = name.as_ref().map(|s| s.as_ref()).unwrap_or("wasm_test").trim_left_matches('$');
let module_instance = program.add_module(module_name, module, None).expect(&format!("Failed adding {} module", module_name)); let module_instance = program.add_module(module_name, module, None).expect(&format!("Failed adding {} module", module_name));
module_instance module_instance
} }
fn try_deserialize(base_dir: &str, module_path: &str) -> Result<elements::Module, elements::Error> { fn try_deserialize(base_dir: &str, module_path: &str) -> Result<elements::Module, elements::Error> {
let mut wasm_path = PathBuf::from(base_dir.clone()); let mut wasm_path = PathBuf::from(base_dir.clone());
wasm_path.push(module_path); wasm_path.push(module_path);
parity_wasm::deserialize_file(&wasm_path) parity_wasm::deserialize_file(&wasm_path)
} }
fn try_load(base_dir: &str, module_path: &str) -> Result<(), InterpreterError> { fn try_load(base_dir: &str, module_path: &str) -> Result<(), InterpreterError> {
let module = try_deserialize(base_dir, module_path).map_err(|e| parity_wasm::interpreter::Error::Program(format!("{:?}", e)))?; let module = try_deserialize(base_dir, module_path).map_err(|e| parity_wasm::interpreter::Error::Program(format!("{:?}", e)))?;
let program = ProgramInstance::new(); let program = ProgramInstance::new();
program.add_module("try_load", module, None).map(|_| ()) program.add_module("try_load", module, None).map(|_| ())
} }
fn runtime_value(test_val: &test::RuntimeValue) -> parity_wasm::RuntimeValue { fn runtime_value(test_val: &test::RuntimeValue) -> parity_wasm::RuntimeValue {
match test_val.value_type.as_ref() { match test_val.value_type.as_ref() {
"i32" => { "i32" => {
let unsigned: u32 = test_val.value.parse().expect("Literal parse error"); let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
parity_wasm::RuntimeValue::I32(unsigned as i32) parity_wasm::RuntimeValue::I32(unsigned as i32)
}, },
"i64" => { "i64" => {
let unsigned: u64 = test_val.value.parse().expect("Literal parse error"); let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
parity_wasm::RuntimeValue::I64(unsigned as i64) parity_wasm::RuntimeValue::I64(unsigned as i64)
}, },
"f32" => { "f32" => {
let unsigned: u32 = test_val.value.parse().expect("Literal parse error"); let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
parity_wasm::RuntimeValue::decode_f32(unsigned) parity_wasm::RuntimeValue::decode_f32(unsigned)
}, },
"f64" => { "f64" => {
let unsigned: u64 = test_val.value.parse().expect("Literal parse error"); let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
parity_wasm::RuntimeValue::decode_f64(unsigned) parity_wasm::RuntimeValue::decode_f64(unsigned)
}, },
_ => panic!("Unknwon runtime value type"), _ => panic!("Unknwon runtime value type"),
} }
} }
fn runtime_values(test_vals: &[test::RuntimeValue]) -> Vec<parity_wasm::RuntimeValue> { fn runtime_values(test_vals: &[test::RuntimeValue]) -> Vec<parity_wasm::RuntimeValue> {
test_vals.iter().map(runtime_value).collect::<Vec<parity_wasm::RuntimeValue>>() test_vals.iter().map(runtime_value).collect::<Vec<parity_wasm::RuntimeValue>>()
} }
fn run_action(program: &ProgramInstance, action: &test::Action) fn run_action(program: &ProgramInstance, action: &test::Action)
-> Result<Option<parity_wasm::RuntimeValue>, InterpreterError> -> Result<Option<parity_wasm::RuntimeValue>, InterpreterError>
{ {
match *action { match *action {
test::Action::Invoke { ref module, ref field, ref args } => { test::Action::Invoke { ref module, ref field, ref args } => {
let module = module.clone().unwrap_or("wasm_test".into()); let module = module.clone().unwrap_or("wasm_test".into());
let module = module.trim_left_matches('$'); let module = module.trim_left_matches('$');
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module)); let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
module.execute_export(&jstring_to_rstring(field), runtime_values(args).into()) module.execute_export(&jstring_to_rstring(field), runtime_values(args).into())
}, },
test::Action::Get { ref module, ref field, .. } => { test::Action::Get { ref module, ref field, .. } => {
let module = module.clone().unwrap_or("wasm_test".into()); let module = module.clone().unwrap_or("wasm_test".into());
let module = module.trim_left_matches('$'); let module = module.trim_left_matches('$');
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module)); let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
let field = jstring_to_rstring(&field); let field = jstring_to_rstring(&field);
module.export_entry(field.as_ref(), &ExportEntryType::Any) module.export_entry(field.as_ref(), &ExportEntryType::Any)
.and_then(|i| match i { .and_then(|i| match i {
elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)), elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)),
_ => Err(InterpreterError::Global(format!("Expected to have exported global with name {}", field))), _ => Err(InterpreterError::Global(format!("Expected to have exported global with name {}", field))),
}) })
.and_then(|g| module.global(g, None, None).map(|g| Some(g.get()))) .and_then(|g| module.global(g, None, None).map(|g| Some(g.get())))
} }
} }
} }
pub struct FixtureParams { pub struct FixtureParams {
failing: bool, failing: bool,
json: String, json: String,
} }
pub fn run_wast2wasm(name: &str) -> FixtureParams { pub fn run_wast2wasm(name: &str) -> FixtureParams {
let outdir = env::var("OUT_DIR").unwrap(); let outdir = env::var("OUT_DIR").unwrap();
let mut wast2wasm_path = PathBuf::from(outdir.clone()); let mut wast2wasm_path = PathBuf::from(outdir.clone());
wast2wasm_path.push("bin"); wast2wasm_path.push("bin");
wast2wasm_path.push("wast2wasm"); wast2wasm_path.push("wast2wasm");
let mut json_spec_path = PathBuf::from(outdir.clone()); let mut json_spec_path = PathBuf::from(outdir.clone());
json_spec_path.push(&format!("{}.json", name)); json_spec_path.push(&format!("{}.json", name));
let wast2wasm_output = Command::new(wast2wasm_path) let wast2wasm_output = Command::new(wast2wasm_path)
.arg("--spec") .arg("--spec")
.arg("-o") .arg("-o")
.arg(&json_spec_path) .arg(&json_spec_path)
.arg(&format!("./wabt/third_party/testsuite/{}.wast", name)) .arg(&format!("./wabt/third_party/testsuite/{}.wast", name))
.output() .output()
.expect("Failed to execute process"); .expect("Failed to execute process");
FixtureParams { FixtureParams {
json: json_spec_path.to_str().unwrap().to_owned(), json: json_spec_path.to_str().unwrap().to_owned(),
failing: { failing: {
if !wast2wasm_output.status.success() { if !wast2wasm_output.status.success() {
println!("wasm2wast error code: {}", wast2wasm_output.status); println!("wasm2wast error code: {}", wast2wasm_output.status);
println!("wasm2wast stdout: {}", String::from_utf8_lossy(&wast2wasm_output.stdout)); println!("wasm2wast stdout: {}", String::from_utf8_lossy(&wast2wasm_output.stdout));
println!("wasm2wast stderr: {}", String::from_utf8_lossy(&wast2wasm_output.stderr)); println!("wasm2wast stderr: {}", String::from_utf8_lossy(&wast2wasm_output.stderr));
true true
} else { } else {
false false
} }
} }
} }
} }
pub fn failing_spec(name: &str) { pub fn failing_spec(name: &str) {
let fixture = run_wast2wasm(name); let fixture = run_wast2wasm(name);
if !fixture.failing { if !fixture.failing {
panic!("wasm2wast expected to fail, but terminated normally"); panic!("wasm2wast expected to fail, but terminated normally");
} }
} }
pub fn spec(name: &str) { pub fn spec(name: &str) {
let outdir = env::var("OUT_DIR").unwrap(); let outdir = env::var("OUT_DIR").unwrap();
let fixture = run_wast2wasm(name); let fixture = run_wast2wasm(name);
if fixture.failing { if fixture.failing {
panic!("wasm2wast terminated abnormally, expected to success"); panic!("wasm2wast terminated abnormally, expected to success");
} }
let mut f = File::open(&fixture.json) let mut f = File::open(&fixture.json)
.expect(&format!("Failed to load json file {}", &fixture.json)); .expect(&format!("Failed to load json file {}", &fixture.json));
let spec: test::Spec = serde_json::from_reader(&mut f).expect("Failed to deserialize JSON file"); let spec: test::Spec = serde_json::from_reader(&mut f).expect("Failed to deserialize JSON file");
let program = ProgramInstance::new(); let program = ProgramInstance::new();
let mut last_module = None; let mut last_module = None;
for command in &spec.commands { for command in &spec.commands {
println!("command {:?}", command); println!("command {:?}", command);
match command { match command {
&test::Command::Module { ref name, ref filename, .. } => { &test::Command::Module { ref name, ref filename, .. } => {
last_module = Some(load_module(&outdir, &filename, &name, &program)); last_module = Some(load_module(&outdir, &filename, &name, &program));
}, },
&test::Command::AssertReturn { line, ref action, ref expected } => { &test::Command::AssertReturn { line, ref action, ref expected } => {
let result = run_action(&program, action); let result = run_action(&program, action);
match result { match result {
Ok(result) => { Ok(result) => {
let spec_expected = runtime_values(expected); let spec_expected = runtime_values(expected);
let actual_result = result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>(); let actual_result = result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>();
for (actual_result, spec_expected) in actual_result.iter().zip(spec_expected.iter()) { for (actual_result, spec_expected) in actual_result.iter().zip(spec_expected.iter()) {
assert_eq!(actual_result.variable_type(), spec_expected.variable_type()); assert_eq!(actual_result.variable_type(), spec_expected.variable_type());
// f32::NAN != f32::NAN // f32::NAN != f32::NAN
match spec_expected { match spec_expected {
&RuntimeValue::F32(val) if val.is_nan() => match actual_result { &RuntimeValue::F32(val) if val.is_nan() => match actual_result {
&RuntimeValue::F32(val) => assert!(val.is_nan()), &RuntimeValue::F32(val) => assert!(val.is_nan()),
_ => unreachable!(), // checked above that types are same _ => unreachable!(), // checked above that types are same
}, },
&RuntimeValue::F64(val) if val.is_nan() => match actual_result { &RuntimeValue::F64(val) if val.is_nan() => match actual_result {
&RuntimeValue::F64(val) => assert!(val.is_nan()), &RuntimeValue::F64(val) => assert!(val.is_nan()),
_ => unreachable!(), // checked above that types are same _ => unreachable!(), // checked above that types are same
}, },
spec_expected @ _ => assert_eq!(actual_result, spec_expected), spec_expected @ _ => assert_eq!(actual_result, spec_expected),
} }
} }
println!("assert_return at line {} - success", line); println!("assert_return at line {} - success", line);
}, },
Err(e) => { Err(e) => {
panic!("Expected action to return value, got error: {:?}", e); panic!("Expected action to return value, got error: {:?}", e);
} }
} }
}, },
&test::Command::AssertReturnCanonicalNan { line, ref action } | &test::Command::AssertReturnArithmeticNan { line, ref action } => { &test::Command::AssertReturnCanonicalNan { line, ref action } | &test::Command::AssertReturnArithmeticNan { line, ref action } => {
let result = run_action(&program, action); let result = run_action(&program, action);
match result { match result {
Ok(result) => { Ok(result) => {
for actual_result in result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>() { for actual_result in result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>() {
match actual_result { match actual_result {
RuntimeValue::F32(val) => if !val.is_nan() { panic!("Expected nan value, got {:?}", val) }, RuntimeValue::F32(val) => if !val.is_nan() { panic!("Expected nan value, got {:?}", val) },
RuntimeValue::F64(val) => if !val.is_nan() { panic!("Expected nan value, got {:?}", val) }, RuntimeValue::F64(val) => if !val.is_nan() { panic!("Expected nan value, got {:?}", val) },
val @ _ => panic!("Expected action to return float value, got {:?}", val), val @ _ => panic!("Expected action to return float value, got {:?}", val),
} }
} }
println!("assert_return_nan at line {} - success", line); println!("assert_return_nan at line {} - success", line);
}, },
Err(e) => { Err(e) => {
panic!("Expected action to return value, got error: {:?}", e); panic!("Expected action to return value, got error: {:?}", e);
} }
} }
}, },
&test::Command::AssertExhaustion { line, ref action, .. } => { &test::Command::AssertExhaustion { line, ref action, .. } => {
let result = run_action(&program, action); let result = run_action(&program, action);
match result { match result {
Ok(result) => panic!("Expected exhaustion, got result: {:?}", result), Ok(result) => panic!("Expected exhaustion, got result: {:?}", result),
Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e), Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e),
} }
}, },
&test::Command::AssertTrap { line, ref action, .. } => { &test::Command::AssertTrap { line, ref action, .. } => {
let result = run_action(&program, action); let result = run_action(&program, action);
match result { match result {
Ok(result) => { Ok(result) => {
panic!("Expected action to result in a trap, got result: {:?}", result); panic!("Expected action to result in a trap, got result: {:?}", result);
}, },
Err(e) => { Err(e) => {
println!("assert_trap at line {} - success ({:?})", line, e); println!("assert_trap at line {} - success ({:?})", line, e);
} }
} }
}, },
&test::Command::AssertInvalid { line, ref filename, .. } &test::Command::AssertInvalid { line, ref filename, .. }
| &test::Command::AssertMalformed { line, ref filename, .. } | &test::Command::AssertMalformed { line, ref filename, .. }
| &test::Command::AssertUnlinkable { line, ref filename, .. } | &test::Command::AssertUnlinkable { line, ref filename, .. }
=> { => {
let module_load = try_load(&outdir, filename); let module_load = try_load(&outdir, filename);
match module_load { match module_load {
Ok(_) => { Ok(_) => {
panic!("Expected invalid module definition, got some module!") panic!("Expected invalid module definition, got some module!")
}, },
Err(e) => { Err(e) => {
println!("assert_invalid at line {} - success ({:?})", line, e) println!("assert_invalid at line {} - success ({:?})", line, e)
} }
} }
}, },
&test::Command::AssertUninstantiable { line, ref filename, .. } => { &test::Command::AssertUninstantiable { line, ref filename, .. } => {
match try_load(&outdir, &filename) { match try_load(&outdir, &filename) {
Ok(_) => panic!("Expected error running start function at line {}", line), Ok(_) => panic!("Expected error running start function at line {}", line),
Err(e) => println!("assert_uninstantiable - success ({:?})", e), Err(e) => println!("assert_uninstantiable - success ({:?})", e),
} }
}, },
&test::Command::Register { ref name, ref as_name, .. } => { &test::Command::Register { ref name, ref as_name, .. } => {
match name { match name {
&Some(ref name) => assert_eq!(name.trim_left_matches('$'), as_name), // we have already registered this module without $ prefix &Some(ref name) => assert_eq!(name.trim_left_matches('$'), as_name), // we have already registered this module without $ prefix
&None => program.insert_loaded_module(as_name, last_module.take().expect("Last module must be set for this command")).map(|_| ()).unwrap(), &None => program.insert_loaded_module(as_name, last_module.take().expect("Last module must be set for this command")).map(|_| ()).unwrap(),
} }
}, },
&test::Command::Action { line, ref action } => { &test::Command::Action { line, ref action } => {
match run_action(&program, action) { match run_action(&program, action) {
Ok(_) => { }, Ok(_) => { },
Err(e) => { Err(e) => {
panic!("Failed to invoke action at line {}: {:?}", line, e) panic!("Failed to invoke action at line {}: {:?}", line, e)
} }
} }
}, },
} }
} }
} }
// Convert json string to correct rust UTF8 string. // Convert json string to correct rust UTF8 string.
@ -287,7 +287,7 @@ pub fn spec(name: &str) {
// It is incorrect. Correct BOM representation in json is "\uFEFF" => we need to do a double utf8-parse here. // It is incorrect. Correct BOM representation in json is "\uFEFF" => we need to do a double utf8-parse here.
// This conversion is incorrect in general case (casting char to u8)!!! // This conversion is incorrect in general case (casting char to u8)!!!
fn jstring_to_rstring(jstring: &str) -> String { fn jstring_to_rstring(jstring: &str) -> String {
let jstring_chars: Vec<u8> = jstring.chars().map(|c| c as u8).collect(); let jstring_chars: Vec<u8> = jstring.chars().map(|c| c as u8).collect();
let rstring = String::from_utf8(jstring_chars).unwrap(); let rstring = String::from_utf8(jstring_chars).unwrap();
rstring rstring
} }

View File

@ -2,103 +2,103 @@
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct RuntimeValue { pub struct RuntimeValue {
#[serde(rename = "type")] #[serde(rename = "type")]
pub value_type: String, pub value_type: String,
pub value: String, pub value: String,
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum Action { pub enum Action {
#[serde(rename = "invoke")] #[serde(rename = "invoke")]
Invoke { Invoke {
module: Option<String>, module: Option<String>,
field: String, field: String,
args: Vec<RuntimeValue>, args: Vec<RuntimeValue>,
}, },
#[serde(rename = "get")] #[serde(rename = "get")]
Get { Get {
module: Option<String>, module: Option<String>,
field: String, field: String,
} }
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum Command { pub enum Command {
#[serde(rename = "module")] #[serde(rename = "module")]
Module { Module {
line: u64, line: u64,
name: Option<String>, name: Option<String>,
filename: String filename: String
}, },
#[serde(rename = "assert_return")] #[serde(rename = "assert_return")]
AssertReturn { AssertReturn {
line: u64, line: u64,
action: Action, action: Action,
expected: Vec<RuntimeValue>, expected: Vec<RuntimeValue>,
}, },
#[serde(rename = "assert_return_canonical_nan")] #[serde(rename = "assert_return_canonical_nan")]
AssertReturnCanonicalNan { AssertReturnCanonicalNan {
line: u64, line: u64,
action: Action, action: Action,
}, },
#[serde(rename = "assert_return_arithmetic_nan")] #[serde(rename = "assert_return_arithmetic_nan")]
AssertReturnArithmeticNan { AssertReturnArithmeticNan {
line: u64, line: u64,
action: Action, action: Action,
}, },
#[serde(rename = "assert_trap")] #[serde(rename = "assert_trap")]
AssertTrap { AssertTrap {
line: u64, line: u64,
action: Action, action: Action,
text: String, text: String,
}, },
#[serde(rename = "assert_invalid")] #[serde(rename = "assert_invalid")]
AssertInvalid { AssertInvalid {
line: u64, line: u64,
filename: String, filename: String,
text: String, text: String,
}, },
#[serde(rename = "assert_malformed")] #[serde(rename = "assert_malformed")]
AssertMalformed { AssertMalformed {
line: u64, line: u64,
filename: String, filename: String,
text: String, text: String,
}, },
#[serde(rename = "assert_uninstantiable")] #[serde(rename = "assert_uninstantiable")]
AssertUninstantiable { AssertUninstantiable {
line: u64, line: u64,
filename: String, filename: String,
text: String, text: String,
}, },
#[serde(rename = "assert_exhaustion")] #[serde(rename = "assert_exhaustion")]
AssertExhaustion { AssertExhaustion {
line: u64, line: u64,
action: Action, action: Action,
}, },
#[serde(rename = "assert_unlinkable")] #[serde(rename = "assert_unlinkable")]
AssertUnlinkable { AssertUnlinkable {
line: u64, line: u64,
filename: String, filename: String,
text: String, text: String,
}, },
#[serde(rename = "register")] #[serde(rename = "register")]
Register { Register {
line: u64, line: u64,
name: Option<String>, name: Option<String>,
#[serde(rename = "as")] #[serde(rename = "as")]
as_name: String, as_name: String,
}, },
#[serde(rename = "action")] #[serde(rename = "action")]
Action { Action {
line: u64, line: u64,
action: Action, action: Action,
}, },
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct Spec { pub struct Spec {
pub source_filename: String, pub source_filename: String,
pub commands: Vec<Command>, pub commands: Vec<Command>,
} }

View File

@ -4,170 +4,170 @@ use super::misc::{ValueTypeBuilder, ValueTypesBuilder, OptionalValueTypeBuilder}
/// Signature template description /// Signature template description
pub enum Signature { pub enum Signature {
TypeReference(u32), TypeReference(u32),
Inline(elements::FunctionType), Inline(elements::FunctionType),
} }
/// Signature builder /// Signature builder
pub struct SignatureBuilder<F=Identity> { pub struct SignatureBuilder<F=Identity> {
callback: F, callback: F,
signature: elements::FunctionType, signature: elements::FunctionType,
} }
impl SignatureBuilder { impl SignatureBuilder {
/// New signature builder /// New signature builder
pub fn new() -> Self { pub fn new() -> Self {
SignatureBuilder::with_callback(Identity) SignatureBuilder::with_callback(Identity)
} }
} }
impl<F> SignatureBuilder<F> where F: Invoke<elements::FunctionType> { impl<F> SignatureBuilder<F> where F: Invoke<elements::FunctionType> {
/// New builder with callback function specified /// New builder with callback function specified
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
SignatureBuilder { SignatureBuilder {
callback: callback, callback: callback,
signature: elements::FunctionType::default(), signature: elements::FunctionType::default(),
} }
} }
/// Add argument to signature builder /// Add argument to signature builder
pub fn with_param(mut self, value_type: elements::ValueType) -> Self { pub fn with_param(mut self, value_type: elements::ValueType) -> Self {
self.signature.params_mut().push(value_type); self.signature.params_mut().push(value_type);
self self
} }
/// Add multiple arguments to signature builder /// Add multiple arguments to signature builder
pub fn with_params(mut self, value_types: Vec<elements::ValueType>) -> Self { pub fn with_params(mut self, value_types: Vec<elements::ValueType>) -> Self {
self.signature.params_mut().extend(value_types); self.signature.params_mut().extend(value_types);
self self
} }
/// Override signature return type /// Override signature return type
pub fn with_return_type(mut self, return_type: Option<elements::ValueType>) -> Self { pub fn with_return_type(mut self, return_type: Option<elements::ValueType>) -> Self {
*self.signature.return_type_mut() = return_type; *self.signature.return_type_mut() = return_type;
self self
} }
/// Start build new argument /// Start build new argument
pub fn param(self) -> ValueTypeBuilder<Self> { pub fn param(self) -> ValueTypeBuilder<Self> {
ValueTypeBuilder::with_callback(self) ValueTypeBuilder::with_callback(self)
} }
/// Start build multiple arguments /// Start build multiple arguments
pub fn params(self) -> ValueTypesBuilder<Self> { pub fn params(self) -> ValueTypesBuilder<Self> {
ValueTypesBuilder::with_callback(self) ValueTypesBuilder::with_callback(self)
} }
/// Start building return type /// Start building return type
pub fn return_type(self) -> OptionalValueTypeBuilder<Self> { pub fn return_type(self) -> OptionalValueTypeBuilder<Self> {
OptionalValueTypeBuilder::with_callback(self) OptionalValueTypeBuilder::with_callback(self)
} }
/// Finish current builder /// Finish current builder
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke(self.signature) self.callback.invoke(self.signature)
} }
/// Finish current builder returning intermediate `Signature` struct /// Finish current builder returning intermediate `Signature` struct
pub fn build_sig(self) -> Signature { pub fn build_sig(self) -> Signature {
Signature::Inline(self.signature) Signature::Inline(self.signature)
} }
} }
impl<F> Invoke<Vec<elements::ValueType>> for SignatureBuilder<F> impl<F> Invoke<Vec<elements::ValueType>> for SignatureBuilder<F>
where F: Invoke<elements::FunctionType> where F: Invoke<elements::FunctionType>
{ {
type Result = Self; type Result = Self;
fn invoke(self, args: Vec<elements::ValueType>) -> Self { fn invoke(self, args: Vec<elements::ValueType>) -> Self {
self.with_params(args) self.with_params(args)
} }
} }
impl<F> Invoke<Option<elements::ValueType>> for SignatureBuilder<F> impl<F> Invoke<Option<elements::ValueType>> for SignatureBuilder<F>
where F: Invoke<elements::FunctionType> where F: Invoke<elements::FunctionType>
{ {
type Result = Self; type Result = Self;
fn invoke(self, arg: Option<elements::ValueType>) -> Self { fn invoke(self, arg: Option<elements::ValueType>) -> Self {
self.with_return_type(arg) self.with_return_type(arg)
} }
} }
impl<F> Invoke<elements::ValueType> for SignatureBuilder<F> impl<F> Invoke<elements::ValueType> for SignatureBuilder<F>
where F: Invoke<elements::FunctionType> where F: Invoke<elements::FunctionType>
{ {
type Result = Self; type Result = Self;
fn invoke(self, arg: elements::ValueType) -> Self { fn invoke(self, arg: elements::ValueType) -> Self {
self.with_param(arg) self.with_param(arg)
} }
} }
/// Type (signature) reference builder (for function/import/indirect call) /// Type (signature) reference builder (for function/import/indirect call)
pub struct TypeRefBuilder<F=Identity> { pub struct TypeRefBuilder<F=Identity> {
callback: F, callback: F,
type_ref: u32, type_ref: u32,
} }
impl<F> TypeRefBuilder<F> where F: Invoke<u32> { impl<F> TypeRefBuilder<F> where F: Invoke<u32> {
/// New builder chained with specified callback /// New builder chained with specified callback
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
TypeRefBuilder { TypeRefBuilder {
callback: callback, callback: callback,
type_ref: 0 type_ref: 0
} }
} }
/// Set/override of type reference /// Set/override of type reference
pub fn val(mut self, val: u32) -> Self { pub fn val(mut self, val: u32) -> Self {
self.type_ref = val; self.type_ref = val;
self self
} }
/// Finish current builder /// Finish current builder
pub fn build(self) -> F::Result { self.callback.invoke(self.type_ref) } pub fn build(self) -> F::Result { self.callback.invoke(self.type_ref) }
} }
/// Multiple signatures builder /// Multiple signatures builder
pub struct SignaturesBuilder<F=Identity> { pub struct SignaturesBuilder<F=Identity> {
callback: F, callback: F,
section: Vec<Signature>, section: Vec<Signature>,
} }
impl SignaturesBuilder { impl SignaturesBuilder {
/// New empty functions section builder /// New empty functions section builder
pub fn new() -> Self { pub fn new() -> Self {
SignaturesBuilder::with_callback(Identity) SignaturesBuilder::with_callback(Identity)
} }
} }
impl<F> SignaturesBuilder<F> { impl<F> SignaturesBuilder<F> {
/// New builder chained with specified callback /// New builder chained with specified callback
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
SignaturesBuilder { SignaturesBuilder {
callback: callback, callback: callback,
section: Vec::new(), section: Vec::new(),
} }
} }
/// Push new signature into the builder output /// Push new signature into the builder output
pub fn with_signature(mut self, signature: Signature) -> Self { pub fn with_signature(mut self, signature: Signature) -> Self {
self.section.push(signature); self.section.push(signature);
self self
} }
/// Start building new signature with `TypeRefBuilder` /// Start building new signature with `TypeRefBuilder`
pub fn type_ref(self) -> TypeRefBuilder<Self> { pub fn type_ref(self) -> TypeRefBuilder<Self> {
TypeRefBuilder::with_callback(self) TypeRefBuilder::with_callback(self)
} }
} }
impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> { impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> {
/// Start building new signature with dedicated builder /// Start building new signature with dedicated builder
pub fn signature(self) -> SignatureBuilder<Self> { pub fn signature(self) -> SignatureBuilder<Self> {
SignatureBuilder::with_callback(self) SignatureBuilder::with_callback(self)
} }
} }
impl<F> Invoke<elements::FunctionType> for SignaturesBuilder<F> { impl<F> Invoke<elements::FunctionType> for SignaturesBuilder<F> {
@ -175,7 +175,7 @@ impl<F> Invoke<elements::FunctionType> for SignaturesBuilder<F> {
fn invoke(self, signature: elements::FunctionType) -> Self { fn invoke(self, signature: elements::FunctionType) -> Self {
self.with_signature(Signature::Inline(signature)) self.with_signature(Signature::Inline(signature))
} }
} }
impl<F> Invoke<u32> for SignaturesBuilder<F> { impl<F> Invoke<u32> for SignaturesBuilder<F> {
@ -183,150 +183,150 @@ impl<F> Invoke<u32> for SignaturesBuilder<F> {
fn invoke(self, type_ref: u32) -> Self { fn invoke(self, type_ref: u32) -> Self {
self.with_signature(Signature::TypeReference(type_ref)) self.with_signature(Signature::TypeReference(type_ref))
} }
} }
impl<F> SignaturesBuilder<F> where F: Invoke<elements::FunctionSection> { impl<F> SignaturesBuilder<F> where F: Invoke<elements::FunctionSection> {
/// Finalize builder spawning element /// Finalize builder spawning element
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
let mut result = elements::FunctionSection::default(); let mut result = elements::FunctionSection::default();
for f in self.section.into_iter() { for f in self.section.into_iter() {
if let Signature::TypeReference(type_ref) = f { if let Signature::TypeReference(type_ref) = f {
result.entries_mut().push(elements::Func::new(type_ref)); result.entries_mut().push(elements::Func::new(type_ref));
} else { } else {
unreachable!(); // never possible with current generics impl-s unreachable!(); // never possible with current generics impl-s
} }
} }
self.callback.invoke(result) self.callback.invoke(result)
} }
} }
/// Signature bindings /// Signature bindings
pub type SignatureBindings = Vec<Signature>; pub type SignatureBindings = Vec<Signature>;
impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> { impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> {
/// Bind signature list /// Bind signature list
pub fn bind(self) -> F::Result { pub fn bind(self) -> F::Result {
self.callback.invoke(self.section) self.callback.invoke(self.section)
} }
} }
/// Function body (code) builder /// Function body (code) builder
pub struct FuncBodyBuilder<F=Identity> { pub struct FuncBodyBuilder<F=Identity> {
callback: F, callback: F,
body: elements::FuncBody, body: elements::FuncBody,
} }
impl<F> FuncBodyBuilder<F> { impl<F> FuncBodyBuilder<F> {
/// New body (code) builder given the chain callback /// New body (code) builder given the chain callback
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
FuncBodyBuilder { FuncBodyBuilder {
callback: callback, callback: callback,
body: elements::FuncBody::new(Vec::new(), elements::Opcodes::empty()), body: elements::FuncBody::new(Vec::new(), elements::Opcodes::empty()),
} }
} }
} }
impl<F> FuncBodyBuilder<F> where F: Invoke<elements::FuncBody> { impl<F> FuncBodyBuilder<F> where F: Invoke<elements::FuncBody> {
/// Set/override entirely with FuncBody struct /// Set/override entirely with FuncBody struct
pub fn with_func(mut self, func: elements::FuncBody) -> Self { pub fn with_func(mut self, func: elements::FuncBody) -> Self {
self.body = func; self.body = func;
self self
} }
/// Extend function local list with new entries /// Extend function local list with new entries
pub fn with_locals(mut self, locals: Vec<elements::Local>) -> Self { pub fn with_locals(mut self, locals: Vec<elements::Local>) -> Self {
self.body.locals_mut().extend(locals); self.body.locals_mut().extend(locals);
self self
} }
/// Set code of the function /// Set code of the function
pub fn with_opcodes(mut self, opcodes: elements::Opcodes) -> Self { pub fn with_opcodes(mut self, opcodes: elements::Opcodes) -> Self {
*self.body.code_mut() = opcodes; *self.body.code_mut() = opcodes;
self self
} }
/// Finish current builder spawning resulting struct /// Finish current builder spawning resulting struct
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke(self.body) self.callback.invoke(self.body)
} }
} }
/// Function definition (extended structure to specify function entirely, incl. signature, mainness and code) /// Function definition (extended structure to specify function entirely, incl. signature, mainness and code)
pub struct FunctionDefinition { pub struct FunctionDefinition {
/// Is this function is start function /// Is this function is start function
pub is_main: bool, pub is_main: bool,
/// Signature description /// Signature description
pub signature: Signature, pub signature: Signature,
/// Body (code) of the function /// Body (code) of the function
pub code: elements::FuncBody, pub code: elements::FuncBody,
} }
impl Default for FunctionDefinition { impl Default for FunctionDefinition {
fn default() -> Self { fn default() -> Self {
FunctionDefinition { FunctionDefinition {
is_main: false, is_main: false,
signature: Signature::TypeReference(0), signature: Signature::TypeReference(0),
code: elements::FuncBody::empty(), code: elements::FuncBody::empty(),
} }
} }
} }
/// Function definition builder /// Function definition builder
pub struct FunctionBuilder<F=Identity> { pub struct FunctionBuilder<F=Identity> {
callback: F, callback: F,
func: FunctionDefinition, func: FunctionDefinition,
} }
impl FunctionBuilder { impl FunctionBuilder {
/// New function builder /// New function builder
pub fn new() -> Self { pub fn new() -> Self {
FunctionBuilder::with_callback(Identity) FunctionBuilder::with_callback(Identity)
} }
} }
impl<F> FunctionBuilder<F> where F: Invoke<FunctionDefinition> { impl<F> FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
/// New function builder with chained callback /// New function builder with chained callback
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
FunctionBuilder { FunctionBuilder {
callback: callback, callback: callback,
func: Default::default(), func: Default::default(),
} }
} }
/// Set that this function is main entry point /// Set that this function is main entry point
pub fn main(mut self) -> Self { pub fn main(mut self) -> Self {
self.func.is_main = true; self.func.is_main = true;
self self
} }
/// Start signature builder of the function /// Start signature builder of the function
pub fn signature(self) -> SignatureBuilder<Self> { pub fn signature(self) -> SignatureBuilder<Self> {
SignatureBuilder::with_callback(self) SignatureBuilder::with_callback(self)
} }
/// Override current signature entirely with new one from known struct /// Override current signature entirely with new one from known struct
pub fn with_signature(mut self, signature: Signature) -> Self { pub fn with_signature(mut self, signature: Signature) -> Self {
self.func.signature = signature; self.func.signature = signature;
self self
} }
/// Start code (body) builder /// Start code (body) builder
pub fn body(self) -> FuncBodyBuilder<Self> { pub fn body(self) -> FuncBodyBuilder<Self> {
FuncBodyBuilder::with_callback(self) FuncBodyBuilder::with_callback(self)
} }
/// Set body (code) for this function /// Set body (code) for this function
pub fn with_body(mut self, body: elements::FuncBody) -> Self { pub fn with_body(mut self, body: elements::FuncBody) -> Self {
self.func.code = body; self.func.code = body;
self self
} }
/// Finalize current builder spawning resulting struct in the callback /// Finalize current builder spawning resulting struct in the callback
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke(self.func) self.callback.invoke(self.func)
} }
} }
impl<F> Invoke<elements::FunctionType> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> { impl<F> Invoke<elements::FunctionType> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
@ -334,7 +334,7 @@ impl<F> Invoke<elements::FunctionType> for FunctionBuilder<F> where F: Invoke<Fu
fn invoke(self, signature: elements::FunctionType) -> Self { fn invoke(self, signature: elements::FunctionType) -> Self {
self.with_signature(Signature::Inline(signature)) self.with_signature(Signature::Inline(signature))
} }
} }
impl<F> Invoke<u32> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> { impl<F> Invoke<u32> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
@ -342,70 +342,70 @@ impl<F> Invoke<u32> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
fn invoke(self, type_ref: u32) -> Self { fn invoke(self, type_ref: u32) -> Self {
self.with_signature(Signature::TypeReference(type_ref)) self.with_signature(Signature::TypeReference(type_ref))
} }
} }
impl<F> Invoke<elements::FuncBody> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> { impl<F> Invoke<elements::FuncBody> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
type Result = Self; type Result = Self;
fn invoke(self, body: elements::FuncBody) -> Self::Result { fn invoke(self, body: elements::FuncBody) -> Self::Result {
self.with_body(body) self.with_body(body)
} }
} }
/// New builder of signature list /// New builder of signature list
pub fn signatures() -> SignaturesBuilder { pub fn signatures() -> SignaturesBuilder {
SignaturesBuilder::new() SignaturesBuilder::new()
} }
/// New signature builder /// New signature builder
pub fn signature() -> SignatureBuilder { pub fn signature() -> SignatureBuilder {
SignatureBuilder::new() SignatureBuilder::new()
} }
/// New builder of function (signature & body) /// New builder of function (signature & body)
pub fn function() -> FunctionBuilder { pub fn function() -> FunctionBuilder {
FunctionBuilder::new() FunctionBuilder::new()
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{signatures, function}; use super::{signatures, function};
use elements; use elements;
#[test] #[test]
fn example() { fn example() {
let result = signatures() let result = signatures()
.type_ref().val(1).build() .type_ref().val(1).build()
.build(); .build();
assert_eq!(result.entries().len(), 1); assert_eq!(result.entries().len(), 1);
let result = signatures() let result = signatures()
.signature() .signature()
.param().i32() .param().i32()
.param().i32() .param().i32()
.return_type().i64() .return_type().i64()
.build() .build()
.bind(); .bind();
assert_eq!(result.len(), 1); assert_eq!(result.len(), 1);
} }
#[test] #[test]
fn func_example() { fn func_example() {
let func = function() let func = function()
.signature() .signature()
.param().i32() .param().i32()
.return_type().i32() .return_type().i32()
.build() .build()
.body() .body()
.with_opcodes(elements::Opcodes::empty()) .with_opcodes(elements::Opcodes::empty())
.build() .build()
.build(); .build();
assert_eq!(func.code.locals().len(), 0); assert_eq!(func.code.locals().len(), 0);
assert_eq!(func.code.code().elements().len(), 1); assert_eq!(func.code.code().elements().len(), 1);
} }
} }

View File

@ -3,53 +3,53 @@ use elements;
/// Data segment builder /// Data segment builder
pub struct DataSegmentBuilder<F=Identity> { pub struct DataSegmentBuilder<F=Identity> {
callback: F, callback: F,
// todo: add mapper once multiple memory refs possible // todo: add mapper once multiple memory refs possible
mem_index: u32, mem_index: u32,
offset: elements::InitExpr, offset: elements::InitExpr,
value: Vec<u8>, value: Vec<u8>,
} }
impl DataSegmentBuilder { impl DataSegmentBuilder {
/// New data segment builder /// New data segment builder
pub fn new() -> Self { pub fn new() -> Self {
DataSegmentBuilder::with_callback(Identity) DataSegmentBuilder::with_callback(Identity)
} }
} }
impl<F> DataSegmentBuilder<F> { impl<F> DataSegmentBuilder<F> {
/// New data segment builder inside the chain context /// New data segment builder inside the chain context
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
DataSegmentBuilder { DataSegmentBuilder {
callback: callback, callback: callback,
mem_index: 0, mem_index: 0,
offset: elements::InitExpr::empty(), offset: elements::InitExpr::empty(),
value: Vec::new(), value: Vec::new(),
} }
} }
/// Set offset initialization opcode. `End` opcode will be added automatically. /// Set offset initialization opcode. `End` opcode will be added automatically.
pub fn offset(mut self, opcode: elements::Opcode) -> Self { pub fn offset(mut self, opcode: elements::Opcode) -> Self {
self.offset = elements::InitExpr::new(vec![opcode, elements::Opcode::End]); self.offset = elements::InitExpr::new(vec![opcode, elements::Opcode::End]);
self self
} }
/// Set the bytes value of the segment /// Set the bytes value of the segment
pub fn value(mut self, value: Vec<u8>) -> Self { pub fn value(mut self, value: Vec<u8>) -> Self {
self.value = value; self.value = value;
self self
} }
} }
impl<F> DataSegmentBuilder<F> where F: Invoke<elements::DataSegment> { impl<F> DataSegmentBuilder<F> where F: Invoke<elements::DataSegment> {
/// Finish current builder, spawning resulting struct /// Finish current builder, spawning resulting struct
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke( self.callback.invoke(
elements::DataSegment::new( elements::DataSegment::new(
self.mem_index, self.mem_index,
self.offset, self.offset,
self.value, self.value,
) )
) )
} }
} }

View File

@ -3,113 +3,113 @@ use elements;
/// Export entry builder /// Export entry builder
pub struct ExportBuilder<F=Identity> { pub struct ExportBuilder<F=Identity> {
callback: F, callback: F,
field: String, field: String,
binding: elements::Internal, binding: elements::Internal,
} }
impl ExportBuilder { impl ExportBuilder {
/// New export builder /// New export builder
pub fn new() -> Self { pub fn new() -> Self {
ExportBuilder::with_callback(Identity) ExportBuilder::with_callback(Identity)
} }
} }
impl<F> ExportBuilder<F> { impl<F> ExportBuilder<F> {
/// New export entry builder in the specified chained context /// New export entry builder in the specified chained context
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
ExportBuilder { ExportBuilder {
callback: callback, callback: callback,
field: String::new(), field: String::new(),
binding: elements::Internal::Function(0), binding: elements::Internal::Function(0),
} }
} }
/// Set the field name of the export entry /// Set the field name of the export entry
pub fn field(mut self, field: &str) -> Self { pub fn field(mut self, field: &str) -> Self {
self.field = field.to_owned(); self.field = field.to_owned();
self self
} }
/// Specify the internal module mapping for this entry /// Specify the internal module mapping for this entry
pub fn with_internal(mut self, external: elements::Internal) -> Self { pub fn with_internal(mut self, external: elements::Internal) -> Self {
self.binding = external; self.binding = external;
self self
} }
/// Start the internal builder for this export entry /// Start the internal builder for this export entry
pub fn internal(self) -> ExportInternalBuilder<Self> { pub fn internal(self) -> ExportInternalBuilder<Self> {
ExportInternalBuilder::with_callback(self) ExportInternalBuilder::with_callback(self)
} }
} }
impl<F> ExportBuilder<F> where F: Invoke<elements::ExportEntry> { impl<F> ExportBuilder<F> where F: Invoke<elements::ExportEntry> {
/// Finalize export entry builder spawning the resulting struct /// Finalize export entry builder spawning the resulting struct
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke(elements::ExportEntry::new(self.field, self.binding)) self.callback.invoke(elements::ExportEntry::new(self.field, self.binding))
} }
} }
impl<F> Invoke<elements::Internal> for ExportBuilder<F> { impl<F> Invoke<elements::Internal> for ExportBuilder<F> {
type Result = Self; type Result = Self;
fn invoke(self, val: elements::Internal) -> Self { fn invoke(self, val: elements::Internal) -> Self {
self.with_internal(val) self.with_internal(val)
} }
} }
/// Internal mapping builder for export entry /// Internal mapping builder for export entry
pub struct ExportInternalBuilder<F=Identity> { pub struct ExportInternalBuilder<F=Identity> {
callback: F, callback: F,
binding: elements::Internal, binding: elements::Internal,
} }
impl<F> ExportInternalBuilder<F> where F: Invoke<elements::Internal> { impl<F> ExportInternalBuilder<F> where F: Invoke<elements::Internal> {
/// New export entry internal mapping for the chained context /// New export entry internal mapping for the chained context
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
ExportInternalBuilder{ ExportInternalBuilder{
callback: callback, callback: callback,
binding: elements::Internal::Function(0), binding: elements::Internal::Function(0),
} }
} }
/// Map to function by index /// Map to function by index
pub fn func(mut self, index: u32) -> F::Result { pub fn func(mut self, index: u32) -> F::Result {
self.binding = elements::Internal::Function(index); self.binding = elements::Internal::Function(index);
self.callback.invoke(self.binding) self.callback.invoke(self.binding)
} }
/// Map to memory /// Map to memory
pub fn memory(mut self, index: u32) -> F::Result { pub fn memory(mut self, index: u32) -> F::Result {
self.binding = elements::Internal::Memory(index); self.binding = elements::Internal::Memory(index);
self.callback.invoke(self.binding) self.callback.invoke(self.binding)
} }
/// Map to table /// Map to table
pub fn table(mut self, index: u32) -> F::Result { pub fn table(mut self, index: u32) -> F::Result {
self.binding = elements::Internal::Table(index); self.binding = elements::Internal::Table(index);
self.callback.invoke(self.binding) self.callback.invoke(self.binding)
} }
/// Map to global /// Map to global
pub fn global(mut self, index: u32) -> F::Result { pub fn global(mut self, index: u32) -> F::Result {
self.binding = elements::Internal::Global(index); self.binding = elements::Internal::Global(index);
self.callback.invoke(self.binding) self.callback.invoke(self.binding)
} }
} }
/// New builder for export entry /// New builder for export entry
pub fn export() -> ExportBuilder { pub fn export() -> ExportBuilder {
ExportBuilder::new() ExportBuilder::new()
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::export; use super::export;
#[test] #[test]
fn example() { fn example() {
let entry = export().field("memory").internal().memory(0).build(); let entry = export().field("memory").internal().memory(0).build();
assert_eq!(entry.field(), "memory"); assert_eq!(entry.field(), "memory");
} }
} }

View File

@ -4,87 +4,87 @@ use elements;
/// Global builder /// Global builder
pub struct GlobalBuilder<F=Identity> { pub struct GlobalBuilder<F=Identity> {
callback: F, callback: F,
value_type: elements::ValueType, value_type: elements::ValueType,
is_mutable: bool, is_mutable: bool,
init_expr: elements::InitExpr, init_expr: elements::InitExpr,
} }
impl GlobalBuilder { impl GlobalBuilder {
/// New global builder /// New global builder
pub fn new() -> Self { pub fn new() -> Self {
GlobalBuilder::with_callback(Identity) GlobalBuilder::with_callback(Identity)
} }
} }
impl<F> GlobalBuilder<F> { impl<F> GlobalBuilder<F> {
/// New global builder with callback (in chained context) /// New global builder with callback (in chained context)
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
GlobalBuilder { GlobalBuilder {
callback: callback, callback: callback,
value_type: elements::ValueType::I32, value_type: elements::ValueType::I32,
init_expr: elements::InitExpr::empty(), init_expr: elements::InitExpr::empty(),
is_mutable: false, is_mutable: false,
} }
} }
/// Set/override resulting global type /// Set/override resulting global type
pub fn with_type(mut self, value_type: elements::ValueType) -> Self { pub fn with_type(mut self, value_type: elements::ValueType) -> Self {
self.value_type = value_type; self.value_type = value_type;
self self
} }
/// Set mutabilty to true /// Set mutabilty to true
pub fn mutable(mut self) -> Self { pub fn mutable(mut self) -> Self {
self.is_mutable = true; self.is_mutable = true;
self self
} }
/// Set initialization expression opcode for this global (`end` opcode will be added automatically) /// Set initialization expression opcode for this global (`end` opcode will be added automatically)
pub fn init_expr(mut self, opcode: elements::Opcode) -> Self { pub fn init_expr(mut self, opcode: elements::Opcode) -> Self {
self.init_expr = elements::InitExpr::new(vec![opcode, elements::Opcode::End]); self.init_expr = elements::InitExpr::new(vec![opcode, elements::Opcode::End]);
self self
} }
/// Start value type builder /// Start value type builder
pub fn value_type(self) -> ValueTypeBuilder<Self> { pub fn value_type(self) -> ValueTypeBuilder<Self> {
ValueTypeBuilder::with_callback(self) ValueTypeBuilder::with_callback(self)
} }
} }
impl<F> GlobalBuilder<F> where F: Invoke<elements::GlobalEntry> { impl<F> GlobalBuilder<F> where F: Invoke<elements::GlobalEntry> {
/// Finalize current builder spawning resulting struct /// Finalize current builder spawning resulting struct
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke( self.callback.invoke(
elements::GlobalEntry::new( elements::GlobalEntry::new(
elements::GlobalType::new(self.value_type, self.is_mutable), elements::GlobalType::new(self.value_type, self.is_mutable),
self.init_expr, self.init_expr,
) )
) )
} }
} }
impl<F> Invoke<elements::ValueType> for GlobalBuilder<F> { impl<F> Invoke<elements::ValueType> for GlobalBuilder<F> {
type Result = Self; type Result = Self;
fn invoke(self, the_type: elements::ValueType) -> Self { fn invoke(self, the_type: elements::ValueType) -> Self {
self.with_type(the_type) self.with_type(the_type)
} }
} }
/// New builder for export entry /// New builder for export entry
pub fn global() -> GlobalBuilder { pub fn global() -> GlobalBuilder {
GlobalBuilder::new() GlobalBuilder::new()
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::global; use super::global;
use elements; use elements;
#[test] #[test]
fn example() { fn example() {
let entry = global().value_type().i32().build(); let entry = global().value_type().i32().build();
assert_eq!(entry.global_type().content_type(), elements::ValueType::I32); assert_eq!(entry.global_type().content_type(), elements::ValueType::I32);
assert_eq!(entry.global_type().is_mutable(), false); assert_eq!(entry.global_type().is_mutable(), false);
} }
} }

View File

@ -3,127 +3,127 @@ use elements;
/// Import builder /// Import builder
pub struct ImportBuilder<F=Identity> { pub struct ImportBuilder<F=Identity> {
callback: F, callback: F,
module: String, module: String,
field: String, field: String,
binding: elements::External, binding: elements::External,
} }
impl ImportBuilder { impl ImportBuilder {
/// New import builder /// New import builder
pub fn new() -> Self { pub fn new() -> Self {
ImportBuilder::with_callback(Identity) ImportBuilder::with_callback(Identity)
} }
} }
impl<F> ImportBuilder<F> { impl<F> ImportBuilder<F> {
/// New import builder with callback (in chained context) /// New import builder with callback (in chained context)
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
ImportBuilder { ImportBuilder {
callback: callback, callback: callback,
module: String::new(), module: String::new(),
field: String::new(), field: String::new(),
binding: elements::External::Function(0), binding: elements::External::Function(0),
} }
} }
/// Set/override module name /// Set/override module name
pub fn module(mut self, name: &str) -> Self { pub fn module(mut self, name: &str) -> Self {
self.module = name.to_owned(); self.module = name.to_owned();
self self
} }
/// Set/override field name /// Set/override field name
pub fn field(mut self, name: &str) -> Self { pub fn field(mut self, name: &str) -> Self {
self.field = name.to_owned(); self.field = name.to_owned();
self self
} }
/// Set/override both module name and field name /// Set/override both module name and field name
pub fn path(self, module: &str, field: &str) -> Self { pub fn path(self, module: &str, field: &str) -> Self {
self.module(module).field(field) self.module(module).field(field)
} }
/// Set/override external mapping for this import /// Set/override external mapping for this import
pub fn with_external(mut self, external: elements::External) -> Self { pub fn with_external(mut self, external: elements::External) -> Self {
self.binding = external; self.binding = external;
self self
} }
/// Start new external mapping builder /// Start new external mapping builder
pub fn external(self) -> ImportExternalBuilder<Self> { pub fn external(self) -> ImportExternalBuilder<Self> {
ImportExternalBuilder::with_callback(self) ImportExternalBuilder::with_callback(self)
} }
} }
impl<F> ImportBuilder<F> where F: Invoke<elements::ImportEntry> { impl<F> ImportBuilder<F> where F: Invoke<elements::ImportEntry> {
/// Finalize current builder spawning the resulting struct /// Finalize current builder spawning the resulting struct
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke(elements::ImportEntry::new(self.module, self.field, self.binding)) self.callback.invoke(elements::ImportEntry::new(self.module, self.field, self.binding))
} }
} }
impl<F> Invoke<elements::External> for ImportBuilder<F> { impl<F> Invoke<elements::External> for ImportBuilder<F> {
type Result = Self; type Result = Self;
fn invoke(self, val: elements::External) -> Self { fn invoke(self, val: elements::External) -> Self {
self.with_external(val) self.with_external(val)
} }
} }
/// Import to external mapping builder /// Import to external mapping builder
pub struct ImportExternalBuilder<F=Identity> { pub struct ImportExternalBuilder<F=Identity> {
callback: F, callback: F,
binding: elements::External, binding: elements::External,
} }
impl<F> ImportExternalBuilder<F> where F: Invoke<elements::External> { impl<F> ImportExternalBuilder<F> where F: Invoke<elements::External> {
/// New import to external mapping builder with callback (in chained context) /// New import to external mapping builder with callback (in chained context)
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
ImportExternalBuilder{ ImportExternalBuilder{
callback: callback, callback: callback,
binding: elements::External::Function(0), binding: elements::External::Function(0),
} }
} }
/// Function mapping with type reference /// Function mapping with type reference
pub fn func(mut self, index: u32) -> F::Result { pub fn func(mut self, index: u32) -> F::Result {
self.binding = elements::External::Function(index); self.binding = elements::External::Function(index);
self.callback.invoke(self.binding) self.callback.invoke(self.binding)
} }
/// Memory mapping with specified limits /// Memory mapping with specified limits
pub fn memory(mut self, min: u32, max: Option<u32>) -> F::Result { pub fn memory(mut self, min: u32, max: Option<u32>) -> F::Result {
self.binding = elements::External::Memory(elements::MemoryType::new(min, max)); self.binding = elements::External::Memory(elements::MemoryType::new(min, max));
self.callback.invoke(self.binding) self.callback.invoke(self.binding)
} }
/// Table mapping with specified limits /// Table mapping with specified limits
pub fn table(mut self, min: u32, max: Option<u32>) -> F::Result { pub fn table(mut self, min: u32, max: Option<u32>) -> F::Result {
self.binding = elements::External::Table(elements::TableType::new(min, max)); self.binding = elements::External::Table(elements::TableType::new(min, max));
self.callback.invoke(self.binding) self.callback.invoke(self.binding)
} }
/// Global mapping with speciifed type and mutability /// Global mapping with speciifed type and mutability
pub fn global(mut self, value_type: elements::ValueType, is_mut: bool) -> F::Result { pub fn global(mut self, value_type: elements::ValueType, is_mut: bool) -> F::Result {
self.binding = elements::External::Global(elements::GlobalType::new(value_type, is_mut)); self.binding = elements::External::Global(elements::GlobalType::new(value_type, is_mut));
self.callback.invoke(self.binding) self.callback.invoke(self.binding)
} }
} }
/// New builder for import entry /// New builder for import entry
pub fn import() -> ImportBuilder { pub fn import() -> ImportBuilder {
ImportBuilder::new() ImportBuilder::new()
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::import; use super::import;
#[test] #[test]
fn example() { fn example() {
let entry = import().module("env").field("memory").external().memory(256, Some(256)).build(); let entry = import().module("env").field("memory").external().memory(256, Some(256)).build();
assert_eq!(entry.module(), "env"); assert_eq!(entry.module(), "env");
assert_eq!(entry.field(), "memory"); assert_eq!(entry.field(), "memory");
} }
} }

View File

@ -4,81 +4,81 @@ use super::invoke::{Invoke, Identity};
/// Memory definition struct /// Memory definition struct
#[derive(Debug)] #[derive(Debug)]
pub struct MemoryDefinition { pub struct MemoryDefinition {
/// Minimum memory size /// Minimum memory size
pub min: u32, pub min: u32,
/// Maximum memory size /// Maximum memory size
pub max: Option<u32>, pub max: Option<u32>,
/// Memory data segments (static regions) /// Memory data segments (static regions)
pub data: Vec<MemoryDataDefinition>, pub data: Vec<MemoryDataDefinition>,
} }
/// Memory static region entry definition /// Memory static region entry definition
#[derive(Debug)] #[derive(Debug)]
pub struct MemoryDataDefinition { pub struct MemoryDataDefinition {
/// Segment initialization expression for offset /// Segment initialization expression for offset
pub offset: elements::InitExpr, pub offset: elements::InitExpr,
/// Raw bytes of static region /// Raw bytes of static region
pub values: Vec<u8>, pub values: Vec<u8>,
} }
/// Memory and static regions builder /// Memory and static regions builder
pub struct MemoryBuilder<F=Identity> { pub struct MemoryBuilder<F=Identity> {
callback: F, callback: F,
memory: MemoryDefinition, memory: MemoryDefinition,
} }
impl MemoryBuilder { impl MemoryBuilder {
/// New memory builder /// New memory builder
pub fn new() -> Self { pub fn new() -> Self {
MemoryBuilder::with_callback(Identity) MemoryBuilder::with_callback(Identity)
} }
} }
impl<F> MemoryBuilder<F> where F: Invoke<MemoryDefinition> { impl<F> MemoryBuilder<F> where F: Invoke<MemoryDefinition> {
/// New memory builder with callback (in chained context) /// New memory builder with callback (in chained context)
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
MemoryBuilder { MemoryBuilder {
callback: callback, callback: callback,
memory: Default::default(), memory: Default::default(),
} }
} }
/// Set/override minimum size /// Set/override minimum size
pub fn with_min(mut self, min: u32) -> Self { pub fn with_min(mut self, min: u32) -> Self {
self.memory.min = min; self.memory.min = min;
self self
} }
/// Set/override maximum size /// Set/override maximum size
pub fn with_max(mut self, max: Option<u32>) -> Self { pub fn with_max(mut self, max: Option<u32>) -> Self {
self.memory.max = max; self.memory.max = max;
self self
} }
/// Push new static region with initialized offset expression and raw bytes /// Push new static region with initialized offset expression and raw bytes
pub fn with_data(mut self, index: u32, values: Vec<u8>) -> Self { pub fn with_data(mut self, index: u32, values: Vec<u8>) -> Self {
self.memory.data.push(MemoryDataDefinition { self.memory.data.push(MemoryDataDefinition {
offset: elements::InitExpr::new(vec![ offset: elements::InitExpr::new(vec![
elements::Opcode::I32Const(index as i32), elements::Opcode::I32Const(index as i32),
elements::Opcode::End, elements::Opcode::End,
]), ]),
values: values, values: values,
}); });
self self
} }
/// Finalize current builder, spawning resulting struct /// Finalize current builder, spawning resulting struct
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke(self.memory) self.callback.invoke(self.memory)
} }
} }
impl Default for MemoryDefinition { impl Default for MemoryDefinition {
fn default() -> Self { fn default() -> Self {
MemoryDefinition { MemoryDefinition {
min: 1, min: 1,
max: None, max: None,
data: Vec::new(), data: Vec::new(),
} }
} }
} }

View File

@ -2,91 +2,91 @@ use super::invoke::{Invoke, Identity};
use elements; use elements;
pub struct ValueTypeBuilder<F=Identity> { pub struct ValueTypeBuilder<F=Identity> {
callback: F, callback: F,
} }
impl<F> ValueTypeBuilder<F> where F: Invoke<elements::ValueType> { impl<F> ValueTypeBuilder<F> where F: Invoke<elements::ValueType> {
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
ValueTypeBuilder { callback: callback } ValueTypeBuilder { callback: callback }
} }
pub fn i32(self) -> F::Result { pub fn i32(self) -> F::Result {
self.callback.invoke(elements::ValueType::I32) self.callback.invoke(elements::ValueType::I32)
} }
pub fn i64(self) -> F::Result { pub fn i64(self) -> F::Result {
self.callback.invoke(elements::ValueType::I64) self.callback.invoke(elements::ValueType::I64)
} }
pub fn f32(self) -> F::Result { pub fn f32(self) -> F::Result {
self.callback.invoke(elements::ValueType::F32) self.callback.invoke(elements::ValueType::F32)
} }
pub fn f64(self) -> F::Result { pub fn f64(self) -> F::Result {
self.callback.invoke(elements::ValueType::F64) self.callback.invoke(elements::ValueType::F64)
} }
} }
pub struct OptionalValueTypeBuilder<F=Identity> { pub struct OptionalValueTypeBuilder<F=Identity> {
callback: F, callback: F,
} }
impl<F> OptionalValueTypeBuilder<F> where F: Invoke<Option<elements::ValueType>> { impl<F> OptionalValueTypeBuilder<F> where F: Invoke<Option<elements::ValueType>> {
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
OptionalValueTypeBuilder { callback: callback } OptionalValueTypeBuilder { callback: callback }
} }
pub fn i32(self) -> F::Result { pub fn i32(self) -> F::Result {
self.callback.invoke(Some(elements::ValueType::I32)) self.callback.invoke(Some(elements::ValueType::I32))
} }
pub fn i64(self) -> F::Result { pub fn i64(self) -> F::Result {
self.callback.invoke(Some(elements::ValueType::I64)) self.callback.invoke(Some(elements::ValueType::I64))
} }
pub fn f32(self) -> F::Result { pub fn f32(self) -> F::Result {
self.callback.invoke(Some(elements::ValueType::F32)) self.callback.invoke(Some(elements::ValueType::F32))
} }
pub fn f64(self) -> F::Result { pub fn f64(self) -> F::Result {
self.callback.invoke(Some(elements::ValueType::F64)) self.callback.invoke(Some(elements::ValueType::F64))
} }
} }
pub struct ValueTypesBuilder<F=Identity> { pub struct ValueTypesBuilder<F=Identity> {
callback: F, callback: F,
value_types: Vec<elements::ValueType>, value_types: Vec<elements::ValueType>,
} }
impl<F> ValueTypesBuilder<F> where F: Invoke<Vec<elements::ValueType>> { impl<F> ValueTypesBuilder<F> where F: Invoke<Vec<elements::ValueType>> {
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
ValueTypesBuilder { ValueTypesBuilder {
callback: callback, callback: callback,
value_types: Vec::new(), value_types: Vec::new(),
} }
} }
pub fn i32(mut self) -> Self { pub fn i32(mut self) -> Self {
self.value_types.push(elements::ValueType::I32); self.value_types.push(elements::ValueType::I32);
self self
} }
pub fn i64(mut self) -> Self { pub fn i64(mut self) -> Self {
self.value_types.push(elements::ValueType::I64); self.value_types.push(elements::ValueType::I64);
self self
} }
pub fn f32(mut self) -> Self { pub fn f32(mut self) -> Self {
self.value_types.push(elements::ValueType::F32); self.value_types.push(elements::ValueType::F32);
self self
} }
pub fn f64(mut self) -> Self { pub fn f64(mut self) -> Self {
self.value_types.push(elements::ValueType::F64); self.value_types.push(elements::ValueType::F64);
self self
} }
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke(self.value_types) self.callback.invoke(self.value_types)
} }
} }

View File

@ -12,8 +12,8 @@ mod global;
mod data; mod data;
pub use self::code::{ pub use self::code::{
signatures, signature, function, SignatureBuilder, SignaturesBuilder, signatures, signature, function, SignatureBuilder, SignaturesBuilder,
FunctionBuilder, TypeRefBuilder, FuncBodyBuilder, FunctionDefinition, FunctionBuilder, TypeRefBuilder, FuncBodyBuilder, FunctionDefinition,
}; };
pub use self::data::DataSegmentBuilder; pub use self::data::DataSegmentBuilder;
pub use self::export::{export, ExportBuilder, ExportInternalBuilder}; pub use self::export::{export, ExportBuilder, ExportInternalBuilder};

View File

@ -7,484 +7,484 @@ use elements;
/// Module builder /// Module builder
pub struct ModuleBuilder<F=Identity> { pub struct ModuleBuilder<F=Identity> {
callback: F, callback: F,
module: ModuleScaffold, module: ModuleScaffold,
} }
/// Location of the internal module function /// Location of the internal module function
pub struct CodeLocation { pub struct CodeLocation {
/// Location (index in 'functions' section) of the signature /// Location (index in 'functions' section) of the signature
pub signature: u32, pub signature: u32,
/// Location (index in the 'code' section) of the body /// Location (index in the 'code' section) of the body
pub body: u32, pub body: u32,
} }
#[derive(Default)] #[derive(Default)]
struct ModuleScaffold { struct ModuleScaffold {
pub types: elements::TypeSection, pub types: elements::TypeSection,
pub import: elements::ImportSection, pub import: elements::ImportSection,
pub functions: elements::FunctionSection, pub functions: elements::FunctionSection,
pub table: elements::TableSection, pub table: elements::TableSection,
pub memory: elements::MemorySection, pub memory: elements::MemorySection,
pub global: elements::GlobalSection, pub global: elements::GlobalSection,
pub export: elements::ExportSection, pub export: elements::ExportSection,
pub start: Option<u32>, pub start: Option<u32>,
pub element: elements::ElementSection, pub element: elements::ElementSection,
pub code: elements::CodeSection, pub code: elements::CodeSection,
pub data: elements::DataSection, pub data: elements::DataSection,
pub other: Vec<elements::Section>, pub other: Vec<elements::Section>,
} }
impl From<elements::Module> for ModuleScaffold { impl From<elements::Module> for ModuleScaffold {
fn from(module: elements::Module) -> Self { fn from(module: elements::Module) -> Self {
let mut types: Option<elements::TypeSection> = None; let mut types: Option<elements::TypeSection> = None;
let mut import: Option<elements::ImportSection> = None; let mut import: Option<elements::ImportSection> = None;
let mut funcs: Option<elements::FunctionSection> = None; let mut funcs: Option<elements::FunctionSection> = None;
let mut table: Option<elements::TableSection> = None; let mut table: Option<elements::TableSection> = None;
let mut memory: Option<elements::MemorySection> = None; let mut memory: Option<elements::MemorySection> = None;
let mut global: Option<elements::GlobalSection> = None; let mut global: Option<elements::GlobalSection> = None;
let mut export: Option<elements::ExportSection> = None; let mut export: Option<elements::ExportSection> = None;
let mut start: Option<u32> = None; let mut start: Option<u32> = None;
let mut element: Option<elements::ElementSection> = None; let mut element: Option<elements::ElementSection> = None;
let mut code: Option<elements::CodeSection> = None; let mut code: Option<elements::CodeSection> = None;
let mut data: Option<elements::DataSection> = None; let mut data: Option<elements::DataSection> = None;
let mut sections = module.into_sections(); let mut sections = module.into_sections();
while let Some(section) = sections.pop() { while let Some(section) = sections.pop() {
match section { match section {
elements::Section::Type(sect) => { types = Some(sect); } elements::Section::Type(sect) => { types = Some(sect); }
elements::Section::Import(sect) => { import = Some(sect); } elements::Section::Import(sect) => { import = Some(sect); }
elements::Section::Function(sect) => { funcs = Some(sect); } elements::Section::Function(sect) => { funcs = Some(sect); }
elements::Section::Table(sect) => { table = Some(sect); } elements::Section::Table(sect) => { table = Some(sect); }
elements::Section::Memory(sect) => { memory = Some(sect); } elements::Section::Memory(sect) => { memory = Some(sect); }
elements::Section::Global(sect) => { global = Some(sect); } elements::Section::Global(sect) => { global = Some(sect); }
elements::Section::Export(sect) => { export = Some(sect); } elements::Section::Export(sect) => { export = Some(sect); }
elements::Section::Start(index) => { start = Some(index); } elements::Section::Start(index) => { start = Some(index); }
elements::Section::Element(sect) => { element = Some(sect); } elements::Section::Element(sect) => { element = Some(sect); }
elements::Section::Code(sect) => { code = Some(sect); } elements::Section::Code(sect) => { code = Some(sect); }
elements::Section::Data(sect) => { data = Some(sect); } elements::Section::Data(sect) => { data = Some(sect); }
_ => {} _ => {}
} }
} }
ModuleScaffold { ModuleScaffold {
types: types.unwrap_or_default(), types: types.unwrap_or_default(),
import: import.unwrap_or_default(), import: import.unwrap_or_default(),
functions: funcs.unwrap_or_default(), functions: funcs.unwrap_or_default(),
table: table.unwrap_or_default(), table: table.unwrap_or_default(),
memory: memory.unwrap_or_default(), memory: memory.unwrap_or_default(),
global: global.unwrap_or_default(), global: global.unwrap_or_default(),
export: export.unwrap_or_default(), export: export.unwrap_or_default(),
start: start, start: start,
element: element.unwrap_or_default(), element: element.unwrap_or_default(),
code: code.unwrap_or_default(), code: code.unwrap_or_default(),
data: data.unwrap_or_default(), data: data.unwrap_or_default(),
other: sections, other: sections,
} }
} }
} }
impl From<ModuleScaffold> for elements::Module { impl From<ModuleScaffold> for elements::Module {
fn from(module: ModuleScaffold) -> Self { fn from(module: ModuleScaffold) -> Self {
let mut sections = Vec::new(); let mut sections = Vec::new();
let types = module.types; let types = module.types;
if types.types().len() > 0 { if types.types().len() > 0 {
sections.push(elements::Section::Type(types)); sections.push(elements::Section::Type(types));
} }
let import = module.import; let import = module.import;
if import.entries().len() > 0 { if import.entries().len() > 0 {
sections.push(elements::Section::Import(import)); sections.push(elements::Section::Import(import));
} }
let functions = module.functions; let functions = module.functions;
if functions.entries().len() > 0 { if functions.entries().len() > 0 {
sections.push(elements::Section::Function(functions)); sections.push(elements::Section::Function(functions));
} }
let table = module.table; let table = module.table;
if table.entries().len() > 0 { if table.entries().len() > 0 {
sections.push(elements::Section::Table(table)); sections.push(elements::Section::Table(table));
} }
let memory = module.memory; let memory = module.memory;
if memory.entries().len() > 0 { if memory.entries().len() > 0 {
sections.push(elements::Section::Memory(memory)); sections.push(elements::Section::Memory(memory));
} }
let global = module.global; let global = module.global;
if global.entries().len() > 0 { if global.entries().len() > 0 {
sections.push(elements::Section::Global(global)); sections.push(elements::Section::Global(global));
} }
let export = module.export; let export = module.export;
if export.entries().len() > 0 { if export.entries().len() > 0 {
sections.push(elements::Section::Export(export)); sections.push(elements::Section::Export(export));
} }
if let Some(start) = module.start { if let Some(start) = module.start {
sections.push(elements::Section::Start(start)); sections.push(elements::Section::Start(start));
} }
let element = module.element; let element = module.element;
if element.entries().len() > 0 { if element.entries().len() > 0 {
sections.push(elements::Section::Element(element)); sections.push(elements::Section::Element(element));
} }
let code = module.code; let code = module.code;
if code.bodies().len() > 0 { if code.bodies().len() > 0 {
sections.push(elements::Section::Code(code)); sections.push(elements::Section::Code(code));
} }
let data = module.data; let data = module.data;
if data.entries().len() > 0 { if data.entries().len() > 0 {
sections.push(elements::Section::Data(data)); sections.push(elements::Section::Data(data));
} }
sections.extend(module.other); sections.extend(module.other);
elements::Module::new(sections) elements::Module::new(sections)
} }
} }
impl ModuleBuilder { impl ModuleBuilder {
/// New empty module builder /// New empty module builder
pub fn new() -> Self { pub fn new() -> Self {
ModuleBuilder::with_callback(Identity) ModuleBuilder::with_callback(Identity)
} }
} }
impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> { impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
/// New module builder with bound callback /// New module builder with bound callback
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
ModuleBuilder { ModuleBuilder {
callback: callback, callback: callback,
module: Default::default(), module: Default::default(),
} }
} }
/// Builder from raw module /// Builder from raw module
pub fn with_module(mut self, module: elements::Module) -> Self { pub fn with_module(mut self, module: elements::Module) -> Self {
self.module = module.into(); self.module = module.into();
self self
} }
/// Fill module with sections from iterator /// Fill module with sections from iterator
pub fn with_sections<I>(mut self, sections: I) -> Self pub fn with_sections<I>(mut self, sections: I) -> Self
where I: IntoIterator<Item=elements::Section> where I: IntoIterator<Item=elements::Section>
{ {
self.module.other.extend(sections); self.module.other.extend(sections);
self self
} }
/// Add additional section /// Add additional section
pub fn with_section(mut self, section: elements::Section) -> Self { pub fn with_section(mut self, section: elements::Section) -> Self {
self.module.other.push(section); self.module.other.push(section);
self self
} }
/// Binds to the type section, creates additional types when required /// Binds to the type section, creates additional types when required
pub fn with_signatures(mut self, bindings: code::SignatureBindings) -> Self { pub fn with_signatures(mut self, bindings: code::SignatureBindings) -> Self {
self.push_signatures(bindings); self.push_signatures(bindings);
self self
} }
/// Push stand-alone function definition, creating sections, signature and code blocks /// Push stand-alone function definition, creating sections, signature and code blocks
/// in corresponding sections. /// in corresponding sections.
/// `FunctionDefinition` can be build using `builder::function` builder /// `FunctionDefinition` can be build using `builder::function` builder
pub fn push_function(&mut self, func: code::FunctionDefinition) -> CodeLocation { pub fn push_function(&mut self, func: code::FunctionDefinition) -> CodeLocation {
let signature = func.signature; let signature = func.signature;
let body = func.code; let body = func.code;
let type_ref = self.resolve_type_ref(signature); let type_ref = self.resolve_type_ref(signature);
self.module.functions.entries_mut().push(elements::Func::new(type_ref)); self.module.functions.entries_mut().push(elements::Func::new(type_ref));
let signature_index = self.module.functions.entries_mut().len() as u32 - 1; let signature_index = self.module.functions.entries_mut().len() as u32 - 1;
self.module.code.bodies_mut().push(body); self.module.code.bodies_mut().push(body);
let body_index = self.module.code.bodies_mut().len() as u32 - 1; let body_index = self.module.code.bodies_mut().len() as u32 - 1;
if func.is_main { if func.is_main {
self.module.start = Some(body_index); self.module.start = Some(body_index);
} }
CodeLocation { CodeLocation {
signature: signature_index, signature: signature_index,
body: body_index, body: body_index,
} }
} }
/// Push linear memory region /// Push linear memory region
pub fn push_memory(&mut self, mut memory: memory::MemoryDefinition) -> u32 { pub fn push_memory(&mut self, mut memory: memory::MemoryDefinition) -> u32 {
let entries = self.module.memory.entries_mut(); let entries = self.module.memory.entries_mut();
entries.push(elements::MemoryType::new(memory.min, memory.max)); entries.push(elements::MemoryType::new(memory.min, memory.max));
let memory_index = (entries.len() - 1) as u32; let memory_index = (entries.len() - 1) as u32;
for data in memory.data.drain(..) { for data in memory.data.drain(..) {
self.module.data.entries_mut() self.module.data.entries_mut()
.push(elements::DataSegment::new(memory_index, data.offset, data.values)) .push(elements::DataSegment::new(memory_index, data.offset, data.values))
} }
memory_index memory_index
} }
/// Push table /// Push table
pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 { pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 {
let entries = self.module.table.entries_mut(); let entries = self.module.table.entries_mut();
entries.push(elements::TableType::new(table.min, table.max)); entries.push(elements::TableType::new(table.min, table.max));
let table_index = (entries.len() - 1) as u32; let table_index = (entries.len() - 1) as u32;
for entry in table.elements.drain(..) { for entry in table.elements.drain(..) {
self.module.element.entries_mut() self.module.element.entries_mut()
.push(elements::ElementSegment::new(table_index, entry.offset, entry.values)) .push(elements::ElementSegment::new(table_index, entry.offset, entry.values))
} }
table_index table_index
} }
fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 { fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 {
match signature { match signature {
code::Signature::Inline(func_type) => { code::Signature::Inline(func_type) => {
// todo: maybe search for existing type // todo: maybe search for existing type
self.module.types.types_mut().push(elements::Type::Function(func_type)); self.module.types.types_mut().push(elements::Type::Function(func_type));
self.module.types.types().len() as u32 - 1 self.module.types.types().len() as u32 - 1
} }
code::Signature::TypeReference(type_ref) => { code::Signature::TypeReference(type_ref) => {
type_ref type_ref
} }
} }
} }
/// Push one function signature, returning it's calling index. /// Push one function signature, returning it's calling index.
/// Can create corresponding type in type section. /// Can create corresponding type in type section.
pub fn push_signature(&mut self, signature: code::Signature) -> u32 { pub fn push_signature(&mut self, signature: code::Signature) -> u32 {
self.resolve_type_ref(signature) self.resolve_type_ref(signature)
} }
/// Push signatures in the module, returning corresponding indices of pushed signatures /// Push signatures in the module, returning corresponding indices of pushed signatures
pub fn push_signatures(&mut self, signatures: code::SignatureBindings) -> Vec<u32> { pub fn push_signatures(&mut self, signatures: code::SignatureBindings) -> Vec<u32> {
signatures.into_iter().map(|binding| signatures.into_iter().map(|binding|
self.resolve_type_ref(binding) self.resolve_type_ref(binding)
).collect() ).collect()
} }
/// Push import entry to module. Not that it does not update calling indices in /// Push import entry to module. Not that it does not update calling indices in
/// function bodies. /// function bodies.
pub fn push_import(&mut self, import: elements::ImportEntry) -> u32 { pub fn push_import(&mut self, import: elements::ImportEntry) -> u32 {
self.module.import.entries_mut().push(import); self.module.import.entries_mut().push(import);
// todo: actually update calling addresses in function bodies // todo: actually update calling addresses in function bodies
// todo: also batch push // todo: also batch push
self.module.import.entries_mut().len() as u32 - 1 self.module.import.entries_mut().len() as u32 - 1
} }
/// Push export entry to module. /// Push export entry to module.
pub fn push_export(&mut self, export: elements::ExportEntry) -> u32 { pub fn push_export(&mut self, export: elements::ExportEntry) -> u32 {
self.module.export.entries_mut().push(export); self.module.export.entries_mut().push(export);
self.module.export.entries_mut().len() as u32 - 1 self.module.export.entries_mut().len() as u32 - 1
} }
/// Add new function using dedicated builder /// Add new function using dedicated builder
pub fn function(self) -> FunctionBuilder<Self> { pub fn function(self) -> FunctionBuilder<Self> {
FunctionBuilder::with_callback(self) FunctionBuilder::with_callback(self)
} }
/// Add new linear memory using dedicated builder /// Add new linear memory using dedicated builder
pub fn memory(self) -> MemoryBuilder<Self> { pub fn memory(self) -> MemoryBuilder<Self> {
MemoryBuilder::with_callback(self) MemoryBuilder::with_callback(self)
} }
/// Add new table using dedicated builder /// Add new table using dedicated builder
pub fn table(self) -> TableBuilder<Self> { pub fn table(self) -> TableBuilder<Self> {
TableBuilder::with_callback(self) TableBuilder::with_callback(self)
} }
/// Define functions section /// Define functions section
pub fn functions(self) -> SignaturesBuilder<Self> { pub fn functions(self) -> SignaturesBuilder<Self> {
SignaturesBuilder::with_callback(self) SignaturesBuilder::with_callback(self)
} }
/// With inserted export entry /// With inserted export entry
pub fn with_export(mut self, entry: elements::ExportEntry) -> Self { pub fn with_export(mut self, entry: elements::ExportEntry) -> Self {
self.module.export.entries_mut().push(entry); self.module.export.entries_mut().push(entry);
self self
} }
/// With inserted import entry /// With inserted import entry
pub fn with_import(mut self, entry: elements::ImportEntry) -> Self { pub fn with_import(mut self, entry: elements::ImportEntry) -> Self {
self.module.import.entries_mut().push(entry); self.module.import.entries_mut().push(entry);
self self
} }
/// Import entry builder /// Import entry builder
/// # Examples /// # Examples
/// ``` /// ```
/// use parity_wasm::builder::module; /// use parity_wasm::builder::module;
/// ///
/// let module = module() /// let module = module()
/// .import() /// .import()
/// .module("env") /// .module("env")
/// .field("memory") /// .field("memory")
/// .external().memory(256, Some(256)) /// .external().memory(256, Some(256))
/// .build() /// .build()
/// .build(); /// .build();
/// ///
/// assert_eq!(module.import_section().expect("import section to exist").entries().len(), 1); /// assert_eq!(module.import_section().expect("import section to exist").entries().len(), 1);
/// ``` /// ```
pub fn import(self) -> import::ImportBuilder<Self> { pub fn import(self) -> import::ImportBuilder<Self> {
import::ImportBuilder::with_callback(self) import::ImportBuilder::with_callback(self)
} }
/// With global variable /// With global variable
pub fn with_global(mut self, global: elements::GlobalEntry) -> Self { pub fn with_global(mut self, global: elements::GlobalEntry) -> Self {
self.module.global.entries_mut().push(global); self.module.global.entries_mut().push(global);
self self
} }
/// With table /// With table
pub fn with_table(mut self, table: elements::TableType) -> Self { pub fn with_table(mut self, table: elements::TableType) -> Self {
self.module.table.entries_mut().push(table); self.module.table.entries_mut().push(table);
self self
} }
/// Export entry builder /// Export entry builder
/// # Examples /// # Examples
/// ``` /// ```
/// use parity_wasm::builder::module; /// use parity_wasm::builder::module;
/// use parity_wasm::elements::Opcode::*; /// use parity_wasm::elements::Opcode::*;
/// ///
/// let module = module() /// let module = module()
/// .global() /// .global()
/// .value_type().i32() /// .value_type().i32()
/// .init_expr(I32Const(0)) /// .init_expr(I32Const(0))
/// .build() /// .build()
/// .export() /// .export()
/// .field("_zero") /// .field("_zero")
/// .internal().global(0) /// .internal().global(0)
/// .build() /// .build()
/// .build(); /// .build();
/// ///
/// assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1); /// assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1);
/// ``` /// ```
pub fn export(self) -> export::ExportBuilder<Self> { pub fn export(self) -> export::ExportBuilder<Self> {
export::ExportBuilder::with_callback(self) export::ExportBuilder::with_callback(self)
} }
/// Glboal entry builder /// Glboal entry builder
/// # Examples /// # Examples
/// ``` /// ```
/// use parity_wasm::builder::module; /// use parity_wasm::builder::module;
/// use parity_wasm::elements::Opcode::*; /// use parity_wasm::elements::Opcode::*;
/// ///
/// let module = module() /// let module = module()
/// .global() /// .global()
/// .value_type().i32() /// .value_type().i32()
/// .init_expr(I32Const(0)) /// .init_expr(I32Const(0))
/// .build() /// .build()
/// .build(); /// .build();
/// ///
/// assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1); /// assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1);
/// ``` /// ```
pub fn global(self) -> global::GlobalBuilder<Self> { pub fn global(self) -> global::GlobalBuilder<Self> {
global::GlobalBuilder::with_callback(self) global::GlobalBuilder::with_callback(self)
} }
/// Add data segment to the builder /// Add data segment to the builder
pub fn with_data_segment(mut self, segment: elements::DataSegment) -> Self { pub fn with_data_segment(mut self, segment: elements::DataSegment) -> Self {
self.module.data.entries_mut().push(segment); self.module.data.entries_mut().push(segment);
self self
} }
/// Data entry builder /// Data entry builder
pub fn data(self) -> data::DataSegmentBuilder<Self> { pub fn data(self) -> data::DataSegmentBuilder<Self> {
data::DataSegmentBuilder::with_callback(self) data::DataSegmentBuilder::with_callback(self)
} }
/// Build module (final step) /// Build module (final step)
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke(self.module.into()) self.callback.invoke(self.module.into())
} }
} }
impl<F> Invoke<elements::FunctionSection> for ModuleBuilder<F> impl<F> Invoke<elements::FunctionSection> for ModuleBuilder<F>
where F: Invoke<elements::Module> where F: Invoke<elements::Module>
{ {
type Result = Self; type Result = Self;
fn invoke(self, section: elements::FunctionSection) -> Self { fn invoke(self, section: elements::FunctionSection) -> Self {
self.with_section(elements::Section::Function(section)) self.with_section(elements::Section::Function(section))
} }
} }
impl<F> Invoke<code::SignatureBindings> for ModuleBuilder<F> impl<F> Invoke<code::SignatureBindings> for ModuleBuilder<F>
where F: Invoke<elements::Module> where F: Invoke<elements::Module>
{ {
type Result = Self; type Result = Self;
fn invoke(self, bindings: code::SignatureBindings) -> Self { fn invoke(self, bindings: code::SignatureBindings) -> Self {
self.with_signatures(bindings) self.with_signatures(bindings)
} }
} }
impl<F> Invoke<code::FunctionDefinition> for ModuleBuilder<F> impl<F> Invoke<code::FunctionDefinition> for ModuleBuilder<F>
where F: Invoke<elements::Module> where F: Invoke<elements::Module>
{ {
type Result = Self; type Result = Self;
fn invoke(self, def: code::FunctionDefinition) -> Self { fn invoke(self, def: code::FunctionDefinition) -> Self {
let mut b = self; let mut b = self;
b.push_function(def); b.push_function(def);
b b
} }
} }
impl<F> Invoke<memory::MemoryDefinition> for ModuleBuilder<F> impl<F> Invoke<memory::MemoryDefinition> for ModuleBuilder<F>
where F: Invoke<elements::Module> where F: Invoke<elements::Module>
{ {
type Result = Self; type Result = Self;
fn invoke(self, def: memory::MemoryDefinition) -> Self { fn invoke(self, def: memory::MemoryDefinition) -> Self {
let mut b = self; let mut b = self;
b.push_memory(def); b.push_memory(def);
b b
} }
} }
impl<F> Invoke<table::TableDefinition> for ModuleBuilder<F> impl<F> Invoke<table::TableDefinition> for ModuleBuilder<F>
where F: Invoke<elements::Module> where F: Invoke<elements::Module>
{ {
type Result = Self; type Result = Self;
fn invoke(self, def: table::TableDefinition) -> Self { fn invoke(self, def: table::TableDefinition) -> Self {
let mut b = self; let mut b = self;
b.push_table(def); b.push_table(def);
b b
} }
} }
impl<F> Invoke<elements::ImportEntry> for ModuleBuilder<F> impl<F> Invoke<elements::ImportEntry> for ModuleBuilder<F>
where F: Invoke<elements::Module> where F: Invoke<elements::Module>
{ {
type Result = Self; type Result = Self;
fn invoke(self, entry: elements::ImportEntry) -> Self::Result { fn invoke(self, entry: elements::ImportEntry) -> Self::Result {
self.with_import(entry) self.with_import(entry)
} }
} }
impl<F> Invoke<elements::ExportEntry> for ModuleBuilder<F> impl<F> Invoke<elements::ExportEntry> for ModuleBuilder<F>
where F: Invoke<elements::Module> where F: Invoke<elements::Module>
{ {
type Result = Self; type Result = Self;
fn invoke(self, entry: elements::ExportEntry) -> Self::Result { fn invoke(self, entry: elements::ExportEntry) -> Self::Result {
self.with_export(entry) self.with_export(entry)
} }
} }
impl<F> Invoke<elements::GlobalEntry> for ModuleBuilder<F> impl<F> Invoke<elements::GlobalEntry> for ModuleBuilder<F>
where F: Invoke<elements::Module> where F: Invoke<elements::Module>
{ {
type Result = Self; type Result = Self;
fn invoke(self, entry: elements::GlobalEntry) -> Self::Result { fn invoke(self, entry: elements::GlobalEntry) -> Self::Result {
self.with_global(entry) self.with_global(entry)
} }
} }
impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F> impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F>
where F: Invoke<elements::Module> where F: Invoke<elements::Module>
{ {
type Result = Self; type Result = Self;
fn invoke(self, segment: elements::DataSegment) -> Self { fn invoke(self, segment: elements::DataSegment) -> Self {
self.with_data_segment(segment) self.with_data_segment(segment)
} }
} }
/// Start new module builder /// Start new module builder
@ -492,7 +492,7 @@ impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F>
/// ///
/// ``` /// ```
/// use parity_wasm::builder; /// use parity_wasm::builder;
/// ///
/// let module = builder::module() /// let module = builder::module()
/// .function() /// .function()
/// .signature().param().i32().build() /// .signature().param().i32().build()
@ -505,66 +505,66 @@ impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F>
/// assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1); /// assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1);
/// ``` /// ```
pub fn module() -> ModuleBuilder { pub fn module() -> ModuleBuilder {
ModuleBuilder::new() ModuleBuilder::new()
} }
/// Start builder to extend existing module /// Start builder to extend existing module
pub fn from_module(module: elements::Module) -> ModuleBuilder { pub fn from_module(module: elements::Module) -> ModuleBuilder {
ModuleBuilder::new().with_module(module) ModuleBuilder::new().with_module(module)
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::module; use super::module;
#[test] #[test]
fn smoky() { fn smoky() {
let module = module().build(); let module = module().build();
assert_eq!(module.sections().len(), 0); assert_eq!(module.sections().len(), 0);
} }
#[test] #[test]
fn functions() { fn functions() {
let module = module() let module = module()
.function() .function()
.signature().param().i32().build() .signature().param().i32().build()
.body().build() .body().build()
.build() .build()
.build(); .build();
assert_eq!(module.type_section().expect("type section to exist").types().len(), 1); assert_eq!(module.type_section().expect("type section to exist").types().len(), 1);
assert_eq!(module.function_section().expect("function section to exist").entries().len(), 1); assert_eq!(module.function_section().expect("function section to exist").entries().len(), 1);
assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1); assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1);
} }
#[test] #[test]
fn export() { fn export() {
let module = module() let module = module()
.export().field("call").internal().func(0).build() .export().field("call").internal().func(0).build()
.build(); .build();
assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1); assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1);
} }
#[test] #[test]
fn global() { fn global() {
let module = module() let module = module()
.global().value_type().i64().mutable().init_expr(::elements::Opcode::I64Const(5)).build() .global().value_type().i64().mutable().init_expr(::elements::Opcode::I64Const(5)).build()
.build(); .build();
assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1); assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1);
} }
#[test] #[test]
fn data() { fn data() {
let module = module() let module = module()
.data() .data()
.offset(::elements::Opcode::I32Const(16)) .offset(::elements::Opcode::I32Const(16))
.value(vec![0u8, 15, 10, 5, 25]) .value(vec![0u8, 15, 10, 5, 25])
.build() .build()
.build(); .build();
assert_eq!(module.data_section().expect("data section to exist").entries().len(), 1); assert_eq!(module.data_section().expect("data section to exist").entries().len(), 1);
} }
} }

View File

@ -4,81 +4,81 @@ use super::invoke::{Invoke, Identity};
/// Table definition /// Table definition
#[derive(Debug)] #[derive(Debug)]
pub struct TableDefinition { pub struct TableDefinition {
/// Minimum length /// Minimum length
pub min: u32, pub min: u32,
/// Maximum length, if any /// Maximum length, if any
pub max: Option<u32>, pub max: Option<u32>,
/// Element segments, if any /// Element segments, if any
pub elements: Vec<TableEntryDefinition>, pub elements: Vec<TableEntryDefinition>,
} }
/// Table elements entry definition /// Table elements entry definition
#[derive(Debug)] #[derive(Debug)]
pub struct TableEntryDefinition { pub struct TableEntryDefinition {
/// Offset initialization expression /// Offset initialization expression
pub offset: elements::InitExpr, pub offset: elements::InitExpr,
/// Values of initialization /// Values of initialization
pub values: Vec<u32>, pub values: Vec<u32>,
} }
/// Table builder /// Table builder
pub struct TableBuilder<F=Identity> { pub struct TableBuilder<F=Identity> {
callback: F, callback: F,
table: TableDefinition, table: TableDefinition,
} }
impl TableBuilder { impl TableBuilder {
/// New table builder /// New table builder
pub fn new() -> Self { pub fn new() -> Self {
TableBuilder::with_callback(Identity) TableBuilder::with_callback(Identity)
} }
} }
impl<F> TableBuilder<F> where F: Invoke<TableDefinition> { impl<F> TableBuilder<F> where F: Invoke<TableDefinition> {
/// New table builder with callback in chained context /// New table builder with callback in chained context
pub fn with_callback(callback: F) -> Self { pub fn with_callback(callback: F) -> Self {
TableBuilder { TableBuilder {
callback: callback, callback: callback,
table: Default::default(), table: Default::default(),
} }
} }
/// Set/override minimum length /// Set/override minimum length
pub fn with_min(mut self, min: u32) -> Self { pub fn with_min(mut self, min: u32) -> Self {
self.table.min = min; self.table.min = min;
self self
} }
/// Set/override maximum length /// Set/override maximum length
pub fn with_max(mut self, max: Option<u32>) -> Self { pub fn with_max(mut self, max: Option<u32>) -> Self {
self.table.max = max; self.table.max = max;
self self
} }
/// Generate initialization expression and element values on specified index /// Generate initialization expression and element values on specified index
pub fn with_element(mut self, index: u32, values: Vec<u32>) -> Self { pub fn with_element(mut self, index: u32, values: Vec<u32>) -> Self {
self.table.elements.push(TableEntryDefinition { self.table.elements.push(TableEntryDefinition {
offset: elements::InitExpr::new(vec![ offset: elements::InitExpr::new(vec![
elements::Opcode::I32Const(index as i32), elements::Opcode::I32Const(index as i32),
elements::Opcode::End, elements::Opcode::End,
]), ]),
values: values, values: values,
}); });
self self
} }
/// Finalize current builder spawning resulting struct /// Finalize current builder spawning resulting struct
pub fn build(self) -> F::Result { pub fn build(self) -> F::Result {
self.callback.invoke(self.table) self.callback.invoke(self.table)
} }
} }
impl Default for TableDefinition { impl Default for TableDefinition {
fn default() -> Self { fn default() -> Self {
TableDefinition { TableDefinition {
min: 0, min: 0,
max: None, max: None,
elements: Vec::new(), elements: Vec::new(),
} }
} }
} }

View File

@ -4,98 +4,98 @@ use super::{Deserialize, Serialize, Error, VarUint7, VarUint32};
/// Internal reference of the exported entry. /// Internal reference of the exported entry.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Internal { pub enum Internal {
/// Function reference. /// Function reference.
Function(u32), Function(u32),
/// Table reference. /// Table reference.
Table(u32), Table(u32),
/// Memory reference. /// Memory reference.
Memory(u32), Memory(u32),
/// Global reference. /// Global reference.
Global(u32), Global(u32),
} }
impl Deserialize for Internal { impl Deserialize for Internal {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let kind = VarUint7::deserialize(reader)?; let kind = VarUint7::deserialize(reader)?;
match kind.into() { match kind.into() {
0x00 => Ok(Internal::Function(VarUint32::deserialize(reader)?.into())), 0x00 => Ok(Internal::Function(VarUint32::deserialize(reader)?.into())),
0x01 => Ok(Internal::Table(VarUint32::deserialize(reader)?.into())), 0x01 => Ok(Internal::Table(VarUint32::deserialize(reader)?.into())),
0x02 => Ok(Internal::Memory(VarUint32::deserialize(reader)?.into())), 0x02 => Ok(Internal::Memory(VarUint32::deserialize(reader)?.into())),
0x03 => Ok(Internal::Global(VarUint32::deserialize(reader)?.into())), 0x03 => Ok(Internal::Global(VarUint32::deserialize(reader)?.into())),
_ => Err(Error::UnknownInternalKind(kind.into())), _ => Err(Error::UnknownInternalKind(kind.into())),
} }
} }
} }
impl Serialize for Internal { impl Serialize for Internal {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
let (bt, arg) = match self { let (bt, arg) = match self {
Internal::Function(arg) => (0x00, arg), Internal::Function(arg) => (0x00, arg),
Internal::Table(arg) => (0x01, arg), Internal::Table(arg) => (0x01, arg),
Internal::Memory(arg) => (0x02, arg), Internal::Memory(arg) => (0x02, arg),
Internal::Global(arg) => (0x03, arg), Internal::Global(arg) => (0x03, arg),
}; };
VarUint7::from(bt).serialize(writer)?; VarUint7::from(bt).serialize(writer)?;
VarUint32::from(arg).serialize(writer)?; VarUint32::from(arg).serialize(writer)?;
Ok(()) Ok(())
} }
} }
/// Export entry. /// Export entry.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ExportEntry { pub struct ExportEntry {
field_str: String, field_str: String,
internal: Internal, internal: Internal,
} }
impl ExportEntry { impl ExportEntry {
/// New export entry /// New export entry
pub fn new(field: String, internal: Internal) -> Self { pub fn new(field: String, internal: Internal) -> Self {
ExportEntry { ExportEntry {
field_str: field, field_str: field,
internal: internal internal: internal
} }
} }
/// Public name /// Public name
pub fn field(&self) -> &str { &self.field_str } pub fn field(&self) -> &str { &self.field_str }
/// Public name (mutable) /// Public name (mutable)
pub fn field_mut(&mut self) -> &mut String { &mut self.field_str } pub fn field_mut(&mut self) -> &mut String { &mut self.field_str }
/// Internal reference of the export entry. /// Internal reference of the export entry.
pub fn internal(&self) -> &Internal { &self.internal } pub fn internal(&self) -> &Internal { &self.internal }
/// Internal reference of the export entry (mutable). /// Internal reference of the export entry (mutable).
pub fn internal_mut(&mut self) -> &mut Internal { &mut self.internal } pub fn internal_mut(&mut self) -> &mut Internal { &mut self.internal }
} }
impl Deserialize for ExportEntry { impl Deserialize for ExportEntry {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let field_str = String::deserialize(reader)?; let field_str = String::deserialize(reader)?;
let internal = Internal::deserialize(reader)?; let internal = Internal::deserialize(reader)?;
Ok(ExportEntry { Ok(ExportEntry {
field_str: field_str, field_str: field_str,
internal: internal, internal: internal,
}) })
} }
} }
impl Serialize for ExportEntry { impl Serialize for ExportEntry {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
self.field_str.serialize(writer)?; self.field_str.serialize(writer)?;
self.internal.serialize(writer)?; self.internal.serialize(writer)?;
Ok(()) Ok(())
} }
} }

View File

@ -1,7 +1,7 @@
use std::io; use std::io;
use super::{ use super::{
Deserialize, Error, ValueType, VarUint32, CountedList, Opcodes, Deserialize, Error, ValueType, VarUint32, CountedList, Opcodes,
Serialize, CountedWriter, CountedListWriter, Serialize, CountedWriter, CountedListWriter,
}; };
/// Function signature (type reference) /// Function signature (type reference)
@ -9,122 +9,122 @@ use super::{
pub struct Func(u32); pub struct Func(u32);
impl Func { impl Func {
/// New function signature /// New function signature
pub fn new(type_ref: u32) -> Self { Func(type_ref) } pub fn new(type_ref: u32) -> Self { Func(type_ref) }
/// Function signature type reference. /// Function signature type reference.
pub fn type_ref(&self) -> u32 { pub fn type_ref(&self) -> u32 {
self.0 self.0
} }
/// Function signature type reference (mutable). /// Function signature type reference (mutable).
pub fn type_ref_mut(&mut self) -> &mut u32 { pub fn type_ref_mut(&mut self) -> &mut u32 {
&mut self.0 &mut self.0
} }
} }
/// Local definition inside the function body. /// Local definition inside the function body.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Local { pub struct Local {
count: u32, count: u32,
value_type: ValueType, value_type: ValueType,
} }
impl Local { impl Local {
/// New local with `count` and `value_type`. /// New local with `count` and `value_type`.
pub fn new(count: u32, value_type: ValueType) -> Self { pub fn new(count: u32, value_type: ValueType) -> Self {
Local { count: count, value_type: value_type } Local { count: count, value_type: value_type }
} }
/// Number of locals with the shared type. /// Number of locals with the shared type.
pub fn count(&self) -> u32 { self.count } pub fn count(&self) -> u32 { self.count }
/// Type of the locals. /// Type of the locals.
pub fn value_type(&self) -> ValueType { self.value_type } pub fn value_type(&self) -> ValueType { self.value_type }
} }
impl Deserialize for Local { impl Deserialize for Local {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let count = VarUint32::deserialize(reader)?; let count = VarUint32::deserialize(reader)?;
let value_type = ValueType::deserialize(reader)?; let value_type = ValueType::deserialize(reader)?;
Ok(Local { count: count.into(), value_type: value_type }) Ok(Local { count: count.into(), value_type: value_type })
} }
} }
impl Serialize for Local { impl Serialize for Local {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
VarUint32::from(self.count).serialize(writer)?; VarUint32::from(self.count).serialize(writer)?;
self.value_type.serialize(writer)?; self.value_type.serialize(writer)?;
Ok(()) Ok(())
} }
} }
/// Function body definition. /// Function body definition.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FuncBody { pub struct FuncBody {
locals: Vec<Local>, locals: Vec<Local>,
opcodes: Opcodes, opcodes: Opcodes,
} }
impl FuncBody { impl FuncBody {
/// New function body with given `locals` and `opcodes` /// New function body with given `locals` and `opcodes`
pub fn new(locals: Vec<Local>, opcodes: Opcodes) -> Self { pub fn new(locals: Vec<Local>, opcodes: Opcodes) -> Self {
FuncBody { locals: locals, opcodes: opcodes } FuncBody { locals: locals, opcodes: opcodes }
} }
/// List of individual opcodes /// List of individual opcodes
pub fn empty() -> Self { pub fn empty() -> Self {
FuncBody { locals: Vec::new(), opcodes: Opcodes::empty() } FuncBody { locals: Vec::new(), opcodes: Opcodes::empty() }
} }
/// Locals declared in function body. /// Locals declared in function body.
pub fn locals(&self) -> &[Local] { &self.locals } pub fn locals(&self) -> &[Local] { &self.locals }
/// Opcode sequence of the function body. Minimal opcode sequence /// Opcode sequence of the function body. Minimal opcode sequence
/// is just `&[Opcode::End]` /// is just `&[Opcode::End]`
pub fn code(&self) -> &Opcodes { &self.opcodes } pub fn code(&self) -> &Opcodes { &self.opcodes }
/// Locals declared in function body (mutable). /// Locals declared in function body (mutable).
pub fn locals_mut(&mut self) -> &mut Vec<Local> { &mut self.locals } pub fn locals_mut(&mut self) -> &mut Vec<Local> { &mut self.locals }
/// Opcode sequence of the function body (mutable). /// Opcode sequence of the function body (mutable).
pub fn code_mut(&mut self) -> &mut Opcodes { &mut self.opcodes } pub fn code_mut(&mut self) -> &mut Opcodes { &mut self.opcodes }
} }
impl Deserialize for FuncBody { impl Deserialize for FuncBody {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
// todo: maybe use reader.take(section_length) // todo: maybe use reader.take(section_length)
let _body_size = VarUint32::deserialize(reader)?; let _body_size = VarUint32::deserialize(reader)?;
let locals: Vec<Local> = CountedList::deserialize(reader)?.into_inner(); let locals: Vec<Local> = CountedList::deserialize(reader)?.into_inner();
let opcodes = Opcodes::deserialize(reader)?; let opcodes = Opcodes::deserialize(reader)?;
Ok(FuncBody { locals: locals, opcodes: opcodes }) Ok(FuncBody { locals: locals, opcodes: opcodes })
} }
} }
impl Serialize for FuncBody { impl Serialize for FuncBody {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
let mut counted_writer = CountedWriter::new(writer); let mut counted_writer = CountedWriter::new(writer);
let data = self.locals; let data = self.locals;
let counted_list = CountedListWriter::<Local, _>( let counted_list = CountedListWriter::<Local, _>(
data.len(), data.len(),
data.into_iter().map(Into::into), data.into_iter().map(Into::into),
); );
counted_list.serialize(&mut counted_writer)?; counted_list.serialize(&mut counted_writer)?;
let code = self.opcodes; let code = self.opcodes;
code.serialize(&mut counted_writer)?; code.serialize(&mut counted_writer)?;
counted_writer.done()?; counted_writer.done()?;
Ok(()) Ok(())
} }
} }

View File

@ -4,47 +4,47 @@ use super::{Deserialize, Serialize, Error, GlobalType, InitExpr};
/// Global entry in the module. /// Global entry in the module.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct GlobalEntry { pub struct GlobalEntry {
global_type: GlobalType, global_type: GlobalType,
init_expr: InitExpr, init_expr: InitExpr,
} }
impl GlobalEntry { impl GlobalEntry {
/// New global entry /// New global entry
pub fn new(global_type: GlobalType, init_expr: InitExpr) -> Self { pub fn new(global_type: GlobalType, init_expr: InitExpr) -> Self {
GlobalEntry { GlobalEntry {
global_type: global_type, global_type: global_type,
init_expr: init_expr, init_expr: init_expr,
} }
} }
/// Global type. /// Global type.
pub fn global_type(&self) -> &GlobalType { &self.global_type } pub fn global_type(&self) -> &GlobalType { &self.global_type }
/// Initialization expression (opcodes) for global. /// Initialization expression (opcodes) for global.
pub fn init_expr(&self) -> &InitExpr { &self.init_expr } pub fn init_expr(&self) -> &InitExpr { &self.init_expr }
/// Global type (mutable) /// Global type (mutable)
pub fn global_type_mut(&mut self) -> &mut GlobalType { &mut self.global_type } pub fn global_type_mut(&mut self) -> &mut GlobalType { &mut self.global_type }
/// Initialization expression (opcodes) for global (mutable) /// Initialization expression (opcodes) for global (mutable)
pub fn init_expr_mut(&mut self) -> &mut InitExpr { &mut self.init_expr } pub fn init_expr_mut(&mut self) -> &mut InitExpr { &mut self.init_expr }
} }
impl Deserialize for GlobalEntry { impl Deserialize for GlobalEntry {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let global_type = GlobalType::deserialize(reader)?; let global_type = GlobalType::deserialize(reader)?;
let init_expr = InitExpr::deserialize(reader)?; let init_expr = InitExpr::deserialize(reader)?;
Ok(GlobalEntry { Ok(GlobalEntry {
global_type: global_type, global_type: global_type,
init_expr: init_expr, init_expr: init_expr,
}) })
} }
} }
impl Serialize for GlobalEntry { impl Serialize for GlobalEntry {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
self.global_type.serialize(writer)?; self.global_type.serialize(writer)?;
self.init_expr.serialize(writer) self.init_expr.serialize(writer)
} }
} }

View File

@ -1,152 +1,152 @@
use std::io; use std::io;
use super::{ use super::{
Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1, Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1,
ValueType, TableElementType ValueType, TableElementType
}; };
/// Global definition struct /// Global definition struct
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct GlobalType { pub struct GlobalType {
content_type: ValueType, content_type: ValueType,
is_mutable: bool, is_mutable: bool,
} }
impl GlobalType { impl GlobalType {
/// New global type /// New global type
pub fn new(content_type: ValueType, is_mutable: bool) -> Self { pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
GlobalType { GlobalType {
content_type: content_type, content_type: content_type,
is_mutable: is_mutable, is_mutable: is_mutable,
} }
} }
/// Type of the global entry /// Type of the global entry
pub fn content_type(&self) -> ValueType { self.content_type } pub fn content_type(&self) -> ValueType { self.content_type }
/// Is global entry is declared as mutable /// Is global entry is declared as mutable
pub fn is_mutable(&self) -> bool { self.is_mutable } pub fn is_mutable(&self) -> bool { self.is_mutable }
} }
impl Deserialize for GlobalType { impl Deserialize for GlobalType {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let content_type = ValueType::deserialize(reader)?; let content_type = ValueType::deserialize(reader)?;
let is_mutable = VarUint1::deserialize(reader)?; let is_mutable = VarUint1::deserialize(reader)?;
Ok(GlobalType { Ok(GlobalType {
content_type: content_type, content_type: content_type,
is_mutable: is_mutable.into(), is_mutable: is_mutable.into(),
}) })
} }
} }
impl Serialize for GlobalType { impl Serialize for GlobalType {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
self.content_type.serialize(writer)?; self.content_type.serialize(writer)?;
VarUint1::from(self.is_mutable).serialize(writer)?; VarUint1::from(self.is_mutable).serialize(writer)?;
Ok(()) Ok(())
} }
} }
/// Table entry /// Table entry
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct TableType { pub struct TableType {
elem_type: TableElementType, elem_type: TableElementType,
limits: ResizableLimits, limits: ResizableLimits,
} }
impl TableType { impl TableType {
/// New table definition /// New table definition
pub fn new(min: u32, max: Option<u32>) -> Self { pub fn new(min: u32, max: Option<u32>) -> Self {
TableType { TableType {
elem_type: TableElementType::AnyFunc, elem_type: TableElementType::AnyFunc,
limits: ResizableLimits::new(min, max), limits: ResizableLimits::new(min, max),
} }
} }
/// Table memory specification /// Table memory specification
pub fn limits(&self) -> &ResizableLimits { &self.limits } pub fn limits(&self) -> &ResizableLimits { &self.limits }
/// Table element type /// Table element type
pub fn elem_type(&self) -> TableElementType { self.elem_type } pub fn elem_type(&self) -> TableElementType { self.elem_type }
} }
impl Deserialize for TableType { impl Deserialize for TableType {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let elem_type = TableElementType::deserialize(reader)?; let elem_type = TableElementType::deserialize(reader)?;
let limits = ResizableLimits::deserialize(reader)?; let limits = ResizableLimits::deserialize(reader)?;
Ok(TableType { Ok(TableType {
elem_type: elem_type, elem_type: elem_type,
limits: limits, limits: limits,
}) })
} }
} }
impl Serialize for TableType { impl Serialize for TableType {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
self.elem_type.serialize(writer)?; self.elem_type.serialize(writer)?;
self.limits.serialize(writer) self.limits.serialize(writer)
} }
} }
/// Memory limits /// Memory limits
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct ResizableLimits { pub struct ResizableLimits {
initial: u32, initial: u32,
maximum: Option<u32>, maximum: Option<u32>,
} }
impl ResizableLimits { impl ResizableLimits {
/// New memory limits definition /// New memory limits definition
pub fn new(min: u32, max: Option<u32>) -> Self { pub fn new(min: u32, max: Option<u32>) -> Self {
ResizableLimits { ResizableLimits {
initial: min, initial: min,
maximum: max, maximum: max,
} }
} }
/// Initial size /// Initial size
pub fn initial(&self) -> u32 { self.initial } pub fn initial(&self) -> u32 { self.initial }
/// Maximum size /// Maximum size
pub fn maximum(&self) -> Option<u32> { self.maximum } pub fn maximum(&self) -> Option<u32> { self.maximum }
} }
impl Deserialize for ResizableLimits { impl Deserialize for ResizableLimits {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let has_max = VarUint1::deserialize(reader)?; let has_max = VarUint1::deserialize(reader)?;
let initial = VarUint32::deserialize(reader)?; let initial = VarUint32::deserialize(reader)?;
let maximum = if has_max.into() { let maximum = if has_max.into() {
Some(VarUint32::deserialize(reader)?.into()) Some(VarUint32::deserialize(reader)?.into())
} else { } else {
None None
}; };
Ok(ResizableLimits { Ok(ResizableLimits {
initial: initial.into(), initial: initial.into(),
maximum: maximum, maximum: maximum,
}) })
} }
} }
impl Serialize for ResizableLimits { impl Serialize for ResizableLimits {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
let max = self.maximum; let max = self.maximum;
VarUint1::from(max.is_some()).serialize(writer)?; VarUint1::from(max.is_some()).serialize(writer)?;
VarUint32::from(self.initial).serialize(writer)?; VarUint32::from(self.initial).serialize(writer)?;
if let Some(val) = max { if let Some(val) = max {
VarUint32::from(val).serialize(writer)?; VarUint32::from(val).serialize(writer)?;
} }
Ok(()) Ok(())
} }
} }
/// Memory entry. /// Memory entry.
@ -154,152 +154,152 @@ impl Serialize for ResizableLimits {
pub struct MemoryType(ResizableLimits); pub struct MemoryType(ResizableLimits);
impl MemoryType { impl MemoryType {
/// New memory definition /// New memory definition
pub fn new(min: u32, max: Option<u32>) -> Self { pub fn new(min: u32, max: Option<u32>) -> Self {
MemoryType(ResizableLimits::new(min, max)) MemoryType(ResizableLimits::new(min, max))
} }
/// Limits of the memory entry. /// Limits of the memory entry.
pub fn limits(&self) -> &ResizableLimits { pub fn limits(&self) -> &ResizableLimits {
&self.0 &self.0
} }
} }
impl Deserialize for MemoryType { impl Deserialize for MemoryType {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
Ok(MemoryType(ResizableLimits::deserialize(reader)?)) Ok(MemoryType(ResizableLimits::deserialize(reader)?))
} }
} }
impl Serialize for MemoryType { impl Serialize for MemoryType {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
self.0.serialize(writer) self.0.serialize(writer)
} }
} }
/// External to local binding. /// External to local binding.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum External { pub enum External {
/// Binds to function with index. /// Binds to function with index.
Function(u32), Function(u32),
/// Describes local table definition to be imported as. /// Describes local table definition to be imported as.
Table(TableType), Table(TableType),
/// Describes local memory definition to be imported as. /// Describes local memory definition to be imported as.
Memory(MemoryType), Memory(MemoryType),
/// Describes local global entry to be imported as. /// Describes local global entry to be imported as.
Global(GlobalType), Global(GlobalType),
} }
impl Deserialize for External { impl Deserialize for External {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let kind = VarUint7::deserialize(reader)?; let kind = VarUint7::deserialize(reader)?;
match kind.into() { match kind.into() {
0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())), 0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
0x01 => Ok(External::Table(TableType::deserialize(reader)?)), 0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)), 0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)), 0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
_ => Err(Error::UnknownExternalKind(kind.into())), _ => Err(Error::UnknownExternalKind(kind.into())),
} }
} }
} }
impl Serialize for External { impl Serialize for External {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
use self::External::*; use self::External::*;
match self { match self {
Function(index) => { Function(index) => {
VarUint7::from(0x00).serialize(writer)?; VarUint7::from(0x00).serialize(writer)?;
VarUint32::from(index).serialize(writer)?; VarUint32::from(index).serialize(writer)?;
}, },
Table(tt) => { Table(tt) => {
VarInt7::from(0x01).serialize(writer)?; VarInt7::from(0x01).serialize(writer)?;
tt.serialize(writer)?; tt.serialize(writer)?;
}, },
Memory(mt) => { Memory(mt) => {
VarInt7::from(0x02).serialize(writer)?; VarInt7::from(0x02).serialize(writer)?;
mt.serialize(writer)?; mt.serialize(writer)?;
}, },
Global(gt) => { Global(gt) => {
VarInt7::from(0x03).serialize(writer)?; VarInt7::from(0x03).serialize(writer)?;
gt.serialize(writer)?; gt.serialize(writer)?;
}, },
} }
Ok(()) Ok(())
} }
} }
/// Import entry. /// Import entry.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ImportEntry { pub struct ImportEntry {
module_str: String, module_str: String,
field_str: String, field_str: String,
external: External, external: External,
} }
impl ImportEntry { impl ImportEntry {
/// New import entry. /// New import entry.
pub fn new(module_str: String, field_str: String, external: External) -> Self { pub fn new(module_str: String, field_str: String, external: External) -> Self {
ImportEntry { ImportEntry {
module_str: module_str, module_str: module_str,
field_str: field_str, field_str: field_str,
external: external, external: external,
} }
} }
/// Module reference of the import entry. /// Module reference of the import entry.
pub fn module(&self) -> &str { &self.module_str } pub fn module(&self) -> &str { &self.module_str }
/// Module reference of the import entry (mutable). /// Module reference of the import entry (mutable).
pub fn module_mut(&mut self) -> &mut String { pub fn module_mut(&mut self) -> &mut String {
&mut self.module_str &mut self.module_str
} }
/// Field reference of the import entry. /// Field reference of the import entry.
pub fn field(&self) -> &str { &self.field_str } pub fn field(&self) -> &str { &self.field_str }
/// Field reference of the import entry (mutable) /// Field reference of the import entry (mutable)
pub fn field_mut(&mut self) -> &mut String { pub fn field_mut(&mut self) -> &mut String {
&mut self.field_str &mut self.field_str
} }
/// Local binidng of the import entry. /// Local binidng of the import entry.
pub fn external(&self) -> &External { &self.external } pub fn external(&self) -> &External { &self.external }
/// Local binidng of the import entry (mutable) /// Local binidng of the import entry (mutable)
pub fn external_mut(&mut self) -> &mut External { &mut self.external } pub fn external_mut(&mut self) -> &mut External { &mut self.external }
} }
impl Deserialize for ImportEntry { impl Deserialize for ImportEntry {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let module_str = String::deserialize(reader)?; let module_str = String::deserialize(reader)?;
let field_str = String::deserialize(reader)?; let field_str = String::deserialize(reader)?;
let external = External::deserialize(reader)?; let external = External::deserialize(reader)?;
Ok(ImportEntry { Ok(ImportEntry {
module_str: module_str, module_str: module_str,
field_str: field_str, field_str: field_str,
external: external, external: external,
}) })
} }
} }
impl Serialize for ImportEntry { impl Serialize for ImportEntry {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
self.module_str.serialize(writer)?; self.module_str.serialize(writer)?;
self.field_str.serialize(writer)?; self.field_str.serialize(writer)?;
self.external.serialize(writer) self.external.serialize(writer)
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -19,16 +19,16 @@ mod name_section;
pub use self::module::{Module, peek_size, ImportCountType}; pub use self::module::{Module, peek_size, ImportCountType};
pub use self::section::{ pub use self::section::{
Section, FunctionSection, CodeSection, MemorySection, DataSection, Section, FunctionSection, CodeSection, MemorySection, DataSection,
ImportSection, ExportSection, GlobalSection, TypeSection, ElementSection, ImportSection, ExportSection, GlobalSection, TypeSection, ElementSection,
TableSection, CustomSection, TableSection, CustomSection,
}; };
pub use self::import_entry::{ImportEntry, ResizableLimits, MemoryType, TableType, GlobalType, External}; pub use self::import_entry::{ImportEntry, ResizableLimits, MemoryType, TableType, GlobalType, External};
pub use self::export_entry::{ExportEntry, Internal}; pub use self::export_entry::{ExportEntry, Internal};
pub use self::global_entry::GlobalEntry; pub use self::global_entry::GlobalEntry;
pub use self::primitives::{ pub use self::primitives::{
VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64, VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64,
Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter, Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter,
}; };
pub use self::types::{Type, ValueType, BlockType, FunctionType, TableElementType}; pub use self::types::{Type, ValueType, BlockType, FunctionType, TableElementType};
pub use self::ops::{Opcode, Opcodes, InitExpr}; pub use self::ops::{Opcode, Opcodes, InitExpr};
@ -36,164 +36,164 @@ pub use self::func::{Func, FuncBody, Local};
pub use self::segment::{ElementSegment, DataSegment}; pub use self::segment::{ElementSegment, DataSegment};
pub use self::index_map::IndexMap; pub use self::index_map::IndexMap;
pub use self::name_section::{ pub use self::name_section::{
NameMap, NameSection, ModuleNameSection, FunctionNameSection, NameMap, NameSection, ModuleNameSection, FunctionNameSection,
LocalNameSection, LocalNameSection,
}; };
/// Deserialization from serial i/o /// Deserialization from serial i/o
pub trait Deserialize : Sized { pub trait Deserialize : Sized {
/// Serialization error produced by deserialization routine. /// Serialization error produced by deserialization routine.
type Error; type Error;
/// Deserialize type from serial i/o /// Deserialize type from serial i/o
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>; fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
} }
/// Serialization to serial i/o /// Serialization to serial i/o
pub trait Serialize { pub trait Serialize {
/// Serialization error produced by serialization routine. /// Serialization error produced by serialization routine.
type Error; type Error;
/// Serialize type to serial i/o /// Serialize type to serial i/o
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>; fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
} }
/// Deserialization/serialization error /// Deserialization/serialization error
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Error { pub enum Error {
/// Unexpected end of input /// Unexpected end of input
UnexpectedEof, UnexpectedEof,
/// Invalid magic /// Invalid magic
InvalidMagic, InvalidMagic,
/// Unsupported version /// Unsupported version
UnsupportedVersion(u32), UnsupportedVersion(u32),
/// Inconsistence between declared and actual length /// Inconsistence between declared and actual length
InconsistentLength { InconsistentLength {
/// Expected length of the definition /// Expected length of the definition
expected: usize, expected: usize,
/// Actual length of the definition /// Actual length of the definition
actual: usize actual: usize
}, },
/// Other static error /// Other static error
Other(&'static str), Other(&'static str),
/// Other allocated error /// Other allocated error
HeapOther(String), HeapOther(String),
/// Invalid/unknown value type declaration /// Invalid/unknown value type declaration
UnknownValueType(i8), UnknownValueType(i8),
/// Invalid/unknown table element type declaration /// Invalid/unknown table element type declaration
UnknownTableElementType(i8), UnknownTableElementType(i8),
/// Non-utf8 string /// Non-utf8 string
NonUtf8String, NonUtf8String,
/// Unknown external kind code /// Unknown external kind code
UnknownExternalKind(u8), UnknownExternalKind(u8),
/// Unknown internal kind code /// Unknown internal kind code
UnknownInternalKind(u8), UnknownInternalKind(u8),
/// Unknown opcode encountered /// Unknown opcode encountered
UnknownOpcode(u8), UnknownOpcode(u8),
/// Invalid VarUint1 value /// Invalid VarUint1 value
InvalidVarUint1(u8), InvalidVarUint1(u8),
/// Invalid VarInt32 value /// Invalid VarInt32 value
InvalidVarInt32, InvalidVarInt32,
/// Invalid VarInt64 value /// Invalid VarInt64 value
InvalidVarInt64, InvalidVarInt64,
} }
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
Error::UnexpectedEof => write!(f, "Unexpected end of input"), Error::UnexpectedEof => write!(f, "Unexpected end of input"),
Error::InvalidMagic => write!(f, "Invalid magic number at start of file"), Error::InvalidMagic => write!(f, "Invalid magic number at start of file"),
Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v), Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v),
Error::InconsistentLength { expected, actual } => { Error::InconsistentLength { expected, actual } => {
write!(f, "Expected length {}, found {}", expected, actual) write!(f, "Expected length {}, found {}", expected, actual)
} }
Error::Other(msg) => write!(f, "{}", msg), Error::Other(msg) => write!(f, "{}", msg),
Error::HeapOther(ref msg) => write!(f, "{}", msg), Error::HeapOther(ref msg) => write!(f, "{}", msg),
Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty), Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty),
Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty), Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty),
Error::NonUtf8String => write!(f, "Non-UTF-8 string"), Error::NonUtf8String => write!(f, "Non-UTF-8 string"),
Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind), Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind),
Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind), Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind),
Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode), Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode),
Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val), Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val),
Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"), Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"),
Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"), Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"),
} }
} }
} }
impl error::Error for Error { impl error::Error for Error {
fn description(&self) -> &str { fn description(&self) -> &str {
match *self { match *self {
Error::UnexpectedEof => "Unexpected end of input", Error::UnexpectedEof => "Unexpected end of input",
Error::InvalidMagic => "Invalid magic number at start of file", Error::InvalidMagic => "Invalid magic number at start of file",
Error::UnsupportedVersion(_) => "Unsupported wasm version", Error::UnsupportedVersion(_) => "Unsupported wasm version",
Error::InconsistentLength { .. } => "Inconsistent length", Error::InconsistentLength { .. } => "Inconsistent length",
Error::Other(msg) => msg, Error::Other(msg) => msg,
Error::HeapOther(ref msg) => &msg[..], Error::HeapOther(ref msg) => &msg[..],
Error::UnknownValueType(_) => "Invalid or unknown value type", Error::UnknownValueType(_) => "Invalid or unknown value type",
Error::UnknownTableElementType(_) => "Unknown table element type", Error::UnknownTableElementType(_) => "Unknown table element type",
Error::NonUtf8String => "Non-UTF-8 string", Error::NonUtf8String => "Non-UTF-8 string",
Error::UnknownExternalKind(_) => "Unknown external kind", Error::UnknownExternalKind(_) => "Unknown external kind",
Error::UnknownInternalKind(_) => "Unknown internal kind", Error::UnknownInternalKind(_) => "Unknown internal kind",
Error::UnknownOpcode(_) => "Unknown opcode", Error::UnknownOpcode(_) => "Unknown opcode",
Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer", Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer",
Error::InvalidVarInt32 => "Not a signed 32-bit integer", Error::InvalidVarInt32 => "Not a signed 32-bit integer",
Error::InvalidVarInt64 => "Not a signed 64-bit integer", Error::InvalidVarInt64 => "Not a signed 64-bit integer",
} }
} }
} }
impl From<io::Error> for Error { impl From<io::Error> for Error {
fn from(err: io::Error) -> Self { fn from(err: io::Error) -> Self {
Error::HeapOther(format!("I/O Error: {}", err)) Error::HeapOther(format!("I/O Error: {}", err))
} }
} }
/// Unparsed part of the module/section /// Unparsed part of the module/section
pub struct Unparsed(pub Vec<u8>); pub struct Unparsed(pub Vec<u8>);
impl Deserialize for Unparsed { impl Deserialize for Unparsed {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let len = VarUint32::deserialize(reader)?.into(); let len = VarUint32::deserialize(reader)?.into();
let mut vec = vec![0u8; len]; let mut vec = vec![0u8; len];
reader.read_exact(&mut vec[..])?; reader.read_exact(&mut vec[..])?;
Ok(Unparsed(vec)) Ok(Unparsed(vec))
} }
} }
impl From<Unparsed> for Vec<u8> { impl From<Unparsed> for Vec<u8> {
fn from(u: Unparsed) -> Vec<u8> { fn from(u: Unparsed) -> Vec<u8> {
u.0 u.0
} }
} }
/// Deserialize module from file. /// Deserialize module from file.
pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> { pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
use std::io::Read; use std::io::Read;
let mut contents = Vec::new(); let mut contents = Vec::new();
::std::fs::File::open(p)?.read_to_end(&mut contents)?; ::std::fs::File::open(p)?.read_to_end(&mut contents)?;
deserialize_buffer(&contents) deserialize_buffer(&contents)
} }
/// Deserialize deserializable type from buffer. /// Deserialize deserializable type from buffer.
pub fn deserialize_buffer<T: Deserialize>(contents: &[u8]) -> Result<T, T::Error> { pub fn deserialize_buffer<T: Deserialize>(contents: &[u8]) -> Result<T, T::Error> {
let mut reader = io::Cursor::new(contents); let mut reader = io::Cursor::new(contents);
T::deserialize(&mut reader) T::deserialize(&mut reader)
} }
/// Create buffer with serialized value. /// Create buffer with serialized value.
pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> { pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> {
let mut buf = Vec::new(); let mut buf = Vec::new();
val.serialize(&mut buf)?; val.serialize(&mut buf)?;
Ok(buf) Ok(buf)
} }
/// Serialize module to the file /// Serialize module to the file
pub fn serialize_to_file<P: AsRef<::std::path::Path>>(p: P, module: Module) -> Result<(), Error> pub fn serialize_to_file<P: AsRef<::std::path::Path>>(p: P, module: Module) -> Result<(), Error>
{ {
let mut io = ::std::fs::File::create(p)?; let mut io = ::std::fs::File::create(p)?;
module.serialize(&mut io) module.serialize(&mut io)
} }

View File

@ -3,8 +3,8 @@ use byteorder::{LittleEndian, ByteOrder};
use super::{Deserialize, Serialize, Error, Uint32, External}; use super::{Deserialize, Serialize, Error, Uint32, External};
use super::section::{ use super::section::{
Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection, Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection,
GlobalSection, TableSection, ElementSection, DataSection, MemorySection GlobalSection, TableSection, ElementSection, DataSection, MemorySection
}; };
use super::name_section::NameSection; use super::name_section::NameSection;
@ -13,494 +13,494 @@ const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6d];
/// WebAssembly module /// WebAssembly module
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Module { pub struct Module {
magic: u32, magic: u32,
version: u32, version: u32,
sections: Vec<Section>, sections: Vec<Section>,
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
/// Type of the import entry to count /// Type of the import entry to count
pub enum ImportCountType { pub enum ImportCountType {
/// Count functions /// Count functions
Function, Function,
/// Count globals /// Count globals
Global, Global,
} }
impl Default for Module { impl Default for Module {
fn default() -> Self { fn default() -> Self {
Module { Module {
magic: LittleEndian::read_u32(&WASM_MAGIC_NUMBER), magic: LittleEndian::read_u32(&WASM_MAGIC_NUMBER),
version: 1, version: 1,
sections: Vec::with_capacity(16), sections: Vec::with_capacity(16),
} }
} }
} }
impl Module { impl Module {
/// New module with sections /// New module with sections
pub fn new(sections: Vec<Section>) -> Self { pub fn new(sections: Vec<Section>) -> Self {
Module { Module {
sections: sections, ..Default::default() sections: sections, ..Default::default()
} }
} }
/// Destructure the module, yielding sections /// Destructure the module, yielding sections
pub fn into_sections(self) -> Vec<Section> { pub fn into_sections(self) -> Vec<Section> {
self.sections self.sections
} }
/// Version of module. /// Version of module.
pub fn version(&self) -> u32 { self.version } pub fn version(&self) -> u32 { self.version }
/// Sections list. /// Sections list.
/// Each known section is optional and may appear at most once. /// Each known section is optional and may appear at most once.
pub fn sections(&self) -> &[Section] { pub fn sections(&self) -> &[Section] {
&self.sections &self.sections
} }
/// Sections list (mutable) /// Sections list (mutable)
/// Each known section is optional and may appear at most once. /// Each known section is optional and may appear at most once.
pub fn sections_mut(&mut self) -> &mut Vec<Section> { pub fn sections_mut(&mut self) -> &mut Vec<Section> {
&mut self.sections &mut self.sections
} }
/// Code section, if any. /// Code section, if any.
pub fn code_section(&self) -> Option<&CodeSection> { pub fn code_section(&self) -> Option<&CodeSection> {
for section in self.sections() { for section in self.sections() {
if let &Section::Code(ref code_section) = section { return Some(code_section); } if let &Section::Code(ref code_section) = section { return Some(code_section); }
} }
None None
} }
/// Types section, if any. /// Types section, if any.
pub fn type_section(&self) -> Option<&TypeSection> { pub fn type_section(&self) -> Option<&TypeSection> {
for section in self.sections() { for section in self.sections() {
if let &Section::Type(ref type_section) = section { return Some(type_section); } if let &Section::Type(ref type_section) = section { return Some(type_section); }
} }
None None
} }
/// Imports section, if any. /// Imports section, if any.
pub fn import_section(&self) -> Option<&ImportSection> { pub fn import_section(&self) -> Option<&ImportSection> {
for section in self.sections() { for section in self.sections() {
if let &Section::Import(ref import_section) = section { return Some(import_section); } if let &Section::Import(ref import_section) = section { return Some(import_section); }
} }
None None
} }
/// Globals section, if any. /// Globals section, if any.
pub fn global_section(&self) -> Option<&GlobalSection> { pub fn global_section(&self) -> Option<&GlobalSection> {
for section in self.sections() { for section in self.sections() {
if let &Section::Global(ref section) = section { return Some(section); } if let &Section::Global(ref section) = section { return Some(section); }
} }
None None
} }
/// Exports section, if any. /// Exports section, if any.
pub fn export_section(&self) -> Option<&ExportSection> { pub fn export_section(&self) -> Option<&ExportSection> {
for section in self.sections() { for section in self.sections() {
if let &Section::Export(ref export_section) = section { return Some(export_section); } if let &Section::Export(ref export_section) = section { return Some(export_section); }
} }
None None
} }
/// Table section, if any. /// Table section, if any.
pub fn table_section(&self) -> Option<&TableSection> { pub fn table_section(&self) -> Option<&TableSection> {
for section in self.sections() { for section in self.sections() {
if let &Section::Table(ref section) = section { return Some(section); } if let &Section::Table(ref section) = section { return Some(section); }
} }
None None
} }
/// Data section, if any. /// Data section, if any.
pub fn data_section(&self) -> Option<&DataSection> { pub fn data_section(&self) -> Option<&DataSection> {
for section in self.sections() { for section in self.sections() {
if let &Section::Data(ref section) = section { return Some(section); } if let &Section::Data(ref section) = section { return Some(section); }
} }
None None
} }
/// Element section, if any. /// Element section, if any.
pub fn elements_section(&self) -> Option<&ElementSection> { pub fn elements_section(&self) -> Option<&ElementSection> {
for section in self.sections() { for section in self.sections() {
if let &Section::Element(ref section) = section { return Some(section); } if let &Section::Element(ref section) = section { return Some(section); }
} }
None None
} }
/// Memory section, if any. /// Memory section, if any.
pub fn memory_section(&self) -> Option<&MemorySection> { pub fn memory_section(&self) -> Option<&MemorySection> {
for section in self.sections() { for section in self.sections() {
if let &Section::Memory(ref section) = section { return Some(section); } if let &Section::Memory(ref section) = section { return Some(section); }
} }
None None
} }
/// Functions signatures section, if any. /// Functions signatures section, if any.
pub fn function_section(&self) -> Option<&FunctionSection> { pub fn function_section(&self) -> Option<&FunctionSection> {
for section in self.sections() { for section in self.sections() {
if let &Section::Function(ref sect) = section { return Some(sect); } if let &Section::Function(ref sect) = section { return Some(sect); }
} }
None None
} }
/// Start section, if any. /// Start section, if any.
pub fn start_section(&self) -> Option<u32> { pub fn start_section(&self) -> Option<u32> {
for section in self.sections() { for section in self.sections() {
if let &Section::Start(sect) = section { return Some(sect); } if let &Section::Start(sect) = section { return Some(sect); }
} }
None None
} }
/// Try to parse name section in place /// Try to parse name section in place
/// Corresponding custom section with proper header will convert to name sections /// Corresponding custom section with proper header will convert to name sections
/// If some of them will fail to be decoded, Err variant is returned with the list of /// If some of them will fail to be decoded, Err variant is returned with the list of
/// (index, Error) tuples of failed sections. /// (index, Error) tuples of failed sections.
pub fn parse_names(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> { pub fn parse_names(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> {
let mut parse_errors = Vec::new(); let mut parse_errors = Vec::new();
for i in 0..self.sections.len() { for i in 0..self.sections.len() {
if let Some(name_section) = { if let Some(name_section) = {
let section = self.sections.get(i).expect("cannot fail because i in range 0..len; qed"); let section = self.sections.get(i).expect("cannot fail because i in range 0..len; qed");
if let Section::Custom(ref custom) = *section { if let Section::Custom(ref custom) = *section {
if custom.name() == "name" { if custom.name() == "name" {
let mut rdr = io::Cursor::new(custom.payload()); let mut rdr = io::Cursor::new(custom.payload());
let name_section = match NameSection::deserialize(&self, &mut rdr) { let name_section = match NameSection::deserialize(&self, &mut rdr) {
Ok(ns) => ns, Ok(ns) => ns,
Err(e) => { parse_errors.push((i, e)); continue; } Err(e) => { parse_errors.push((i, e)); continue; }
}; };
Some(name_section) Some(name_section)
} else { } else {
None None
} }
} else { None } } else { None }
} { } {
*self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section); *self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section);
} }
} }
if parse_errors.len() > 0 { if parse_errors.len() > 0 {
Err((parse_errors, self)) Err((parse_errors, self))
} else { } else {
Ok(self) Ok(self)
} }
} }
/// Count imports by provided type /// Count imports by provided type
pub fn import_count(&self, count_type: ImportCountType) -> usize { pub fn import_count(&self, count_type: ImportCountType) -> usize {
self.import_section() self.import_section()
.map(|is| .map(|is|
is.entries().iter().filter(|import| match (count_type, *import.external()) { is.entries().iter().filter(|import| match (count_type, *import.external()) {
(ImportCountType::Function, External::Function(_)) => true, (ImportCountType::Function, External::Function(_)) => true,
(ImportCountType::Global, External::Global(_)) => true, (ImportCountType::Global, External::Global(_)) => true,
_ => false _ => false
}).count()) }).count())
.unwrap_or(0) .unwrap_or(0)
} }
/// Query functions space /// Query functions space
pub fn functions_space(&self) -> usize { pub fn functions_space(&self) -> usize {
self.import_count(ImportCountType::Function) + self.import_count(ImportCountType::Function) +
self.function_section().map(|fs| fs.entries().len()).unwrap_or(0) self.function_section().map(|fs| fs.entries().len()).unwrap_or(0)
} }
/// Query globals space /// Query globals space
pub fn globals_space(&self) -> usize { pub fn globals_space(&self) -> usize {
self.import_count(ImportCountType::Global) + self.import_count(ImportCountType::Global) +
self.global_section().map(|gs| gs.entries().len()).unwrap_or(0) self.global_section().map(|gs| gs.entries().len()).unwrap_or(0)
} }
} }
impl Deserialize for Module { impl Deserialize for Module {
type Error = super::Error; type Error = super::Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let mut sections = Vec::new(); let mut sections = Vec::new();
let mut magic = [0u8; 4]; let mut magic = [0u8; 4];
reader.read(&mut magic)?; reader.read(&mut magic)?;
if magic != WASM_MAGIC_NUMBER { if magic != WASM_MAGIC_NUMBER {
return Err(Error::InvalidMagic); return Err(Error::InvalidMagic);
} }
let version: u32 = Uint32::deserialize(reader)?.into(); let version: u32 = Uint32::deserialize(reader)?.into();
if version != 1 { if version != 1 {
return Err(Error::UnsupportedVersion(version)); return Err(Error::UnsupportedVersion(version));
} }
loop { loop {
match Section::deserialize(reader) { match Section::deserialize(reader) {
Err(Error::UnexpectedEof) => { break; }, Err(Error::UnexpectedEof) => { break; },
Err(e) => { return Err(e) }, Err(e) => { return Err(e) },
Ok(section) => { sections.push(section); } Ok(section) => { sections.push(section); }
} }
} }
Ok(Module { Ok(Module {
magic: LittleEndian::read_u32(&magic), magic: LittleEndian::read_u32(&magic),
version: version, version: version,
sections: sections, sections: sections,
}) })
} }
} }
impl Serialize for Module { impl Serialize for Module {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> {
Uint32::from(self.magic).serialize(w)?; Uint32::from(self.magic).serialize(w)?;
Uint32::from(self.version).serialize(w)?; Uint32::from(self.version).serialize(w)?;
for section in self.sections.into_iter() { for section in self.sections.into_iter() {
section.serialize(w)?; section.serialize(w)?;
} }
Ok(()) Ok(())
} }
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
struct PeekSection<'a> { struct PeekSection<'a> {
cursor: usize, cursor: usize,
region: &'a [u8], region: &'a [u8],
} }
impl<'a> io::Read for PeekSection<'a> { impl<'a> io::Read for PeekSection<'a> {
fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
let available = ::std::cmp::min(buf.len(), self.region.len() - self.cursor); let available = ::std::cmp::min(buf.len(), self.region.len() - self.cursor);
if available < buf.len() { if available < buf.len() {
return Err(::std::io::Error::from(::std::io::ErrorKind::UnexpectedEof)); return Err(::std::io::Error::from(::std::io::ErrorKind::UnexpectedEof));
} }
let range = self.cursor..self.cursor + buf.len(); let range = self.cursor..self.cursor + buf.len();
buf.copy_from_slice(&self.region[range]); buf.copy_from_slice(&self.region[range]);
self.cursor += available; self.cursor += available;
Ok(available) Ok(available)
} }
} }
/// Returns size of the module in the provided stream /// Returns size of the module in the provided stream
pub fn peek_size(source: &[u8]) -> usize { pub fn peek_size(source: &[u8]) -> usize {
if source.len() < 9 { if source.len() < 9 {
return 0; return 0;
} }
let mut cursor = 8; let mut cursor = 8;
loop { loop {
let (new_cursor, section_id, section_len) = { let (new_cursor, section_id, section_len) = {
let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] }; let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] };
let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) { let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) {
Ok(res) => res.into(), Ok(res) => res.into(),
Err(_) => { break; }, Err(_) => { break; },
}; };
let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) { let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) {
Ok(res) => res.into(), Ok(res) => res.into(),
Err(_) => { break; }, Err(_) => { break; },
}; };
(peek_section.cursor, section_id, section_len) (peek_section.cursor, section_id, section_len)
}; };
if section_id <= 11 && section_len > 0 { if section_id <= 11 && section_len > 0 {
let next_cursor = cursor + new_cursor + section_len as usize; let next_cursor = cursor + new_cursor + section_len as usize;
if next_cursor >= source.len() { if next_cursor >= source.len() {
break; break;
} }
cursor = next_cursor; cursor = next_cursor;
} else { } else {
break; break;
} }
} }
cursor cursor
} }
#[cfg(test)] #[cfg(test)]
mod integration_tests { mod integration_tests {
use super::super::{deserialize_file, serialize, deserialize_buffer, Section}; use super::super::{deserialize_file, serialize, deserialize_buffer, Section};
use super::Module; use super::Module;
#[test] #[test]
fn hello() { fn hello() {
let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized"); let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");
assert_eq!(module.version(), 1); assert_eq!(module.version(), 1);
assert_eq!(module.sections().len(), 8); assert_eq!(module.sections().len(), 8);
} }
#[test] #[test]
fn serde() { fn serde() {
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
let buf = serialize(module).expect("serialization to succeed"); let buf = serialize(module).expect("serialization to succeed");
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed"); let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
assert_eq!(module_old.sections().len(), module_new.sections().len()); assert_eq!(module_old.sections().len(), module_new.sections().len());
} }
#[test] #[test]
fn serde_type() { fn serde_type() {
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
module.sections_mut().retain(|x| { module.sections_mut().retain(|x| {
if let &Section::Type(_) = x { true } else { false } if let &Section::Type(_) = x { true } else { false }
}); });
let buf = serialize(module).expect("serialization to succeed"); let buf = serialize(module).expect("serialization to succeed");
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed"); let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
assert_eq!( assert_eq!(
module_old.type_section().expect("type section exists").types().len(), module_old.type_section().expect("type section exists").types().len(),
module_new.type_section().expect("type section exists").types().len(), module_new.type_section().expect("type section exists").types().len(),
"There should be equal amount of types before and after serialization" "There should be equal amount of types before and after serialization"
); );
} }
#[test] #[test]
fn serde_import() { fn serde_import() {
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
module.sections_mut().retain(|x| { module.sections_mut().retain(|x| {
if let &Section::Import(_) = x { true } else { false } if let &Section::Import(_) = x { true } else { false }
}); });
let buf = serialize(module).expect("serialization to succeed"); let buf = serialize(module).expect("serialization to succeed");
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed"); let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
assert_eq!( assert_eq!(
module_old.import_section().expect("import section exists").entries().len(), module_old.import_section().expect("import section exists").entries().len(),
module_new.import_section().expect("import section exists").entries().len(), module_new.import_section().expect("import section exists").entries().len(),
"There should be equal amount of import entries before and after serialization" "There should be equal amount of import entries before and after serialization"
); );
} }
#[test] #[test]
fn serde_code() { fn serde_code() {
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
module.sections_mut().retain(|x| { module.sections_mut().retain(|x| {
if let &Section::Code(_) = x { true } else { false } if let &Section::Code(_) = x { true } else { false }
}); });
let buf = serialize(module).expect("serialization to succeed"); let buf = serialize(module).expect("serialization to succeed");
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed"); let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
assert_eq!( assert_eq!(
module_old.code_section().expect("code section exists").bodies().len(), module_old.code_section().expect("code section exists").bodies().len(),
module_new.code_section().expect("code section exists").bodies().len(), module_new.code_section().expect("code section exists").bodies().len(),
"There should be equal amount of function bodies before and after serialization" "There should be equal amount of function bodies before and after serialization"
); );
} }
#[test] #[test]
fn const_() { fn const_() {
use super::super::Opcode::*; use super::super::Opcode::*;
let module = deserialize_file("./res/cases/v1/const.wasm").expect("Should be deserialized"); let module = deserialize_file("./res/cases/v1/const.wasm").expect("Should be deserialized");
let func = &module.code_section().expect("Code section to exist").bodies()[0]; let func = &module.code_section().expect("Code section to exist").bodies()[0];
assert_eq!(func.code().elements().len(), 20); assert_eq!(func.code().elements().len(), 20);
assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]); assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]);
assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]); assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]);
assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]); assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]);
assert_eq!(I64Const(-8192), func.code().elements()[3]); assert_eq!(I64Const(-8192), func.code().elements()[3]);
assert_eq!(I32Const(1024), func.code().elements()[4]); assert_eq!(I32Const(1024), func.code().elements()[4]);
assert_eq!(I32Const(2048), func.code().elements()[5]); assert_eq!(I32Const(2048), func.code().elements()[5]);
assert_eq!(I32Const(4096), func.code().elements()[6]); assert_eq!(I32Const(4096), func.code().elements()[6]);
assert_eq!(I32Const(8192), func.code().elements()[7]); assert_eq!(I32Const(8192), func.code().elements()[7]);
assert_eq!(I32Const(16384), func.code().elements()[8]); assert_eq!(I32Const(16384), func.code().elements()[8]);
assert_eq!(I32Const(32767), func.code().elements()[9]); assert_eq!(I32Const(32767), func.code().elements()[9]);
assert_eq!(I32Const(-1024), func.code().elements()[10]); assert_eq!(I32Const(-1024), func.code().elements()[10]);
assert_eq!(I32Const(-2048), func.code().elements()[11]); assert_eq!(I32Const(-2048), func.code().elements()[11]);
assert_eq!(I32Const(-4096), func.code().elements()[12]); assert_eq!(I32Const(-4096), func.code().elements()[12]);
assert_eq!(I32Const(-8192), func.code().elements()[13]); assert_eq!(I32Const(-8192), func.code().elements()[13]);
assert_eq!(I32Const(-16384), func.code().elements()[14]); assert_eq!(I32Const(-16384), func.code().elements()[14]);
assert_eq!(I32Const(-32768), func.code().elements()[15]); assert_eq!(I32Const(-32768), func.code().elements()[15]);
assert_eq!(I32Const(-2147483648), func.code().elements()[16]); assert_eq!(I32Const(-2147483648), func.code().elements()[16]);
assert_eq!(I32Const(2147483647), func.code().elements()[17]); assert_eq!(I32Const(2147483647), func.code().elements()[17]);
} }
#[test] #[test]
fn store() { fn store() {
use super::super::Opcode::*; use super::super::Opcode::*;
let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized"); let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
let func = &module.code_section().expect("Code section to exist").bodies()[0]; let func = &module.code_section().expect("Code section to exist").bodies()[0];
assert_eq!(func.code().elements().len(), 5); assert_eq!(func.code().elements().len(), 5);
assert_eq!(I64Store(0, 32), func.code().elements()[2]); assert_eq!(I64Store(0, 32), func.code().elements()[2]);
} }
#[test] #[test]
fn peek() { fn peek() {
use super::peek_size; use super::peek_size;
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized"); let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
let mut buf = serialize(module).expect("serialization to succeed"); let mut buf = serialize(module).expect("serialization to succeed");
buf.extend_from_slice(&[1, 5, 12, 17]); buf.extend_from_slice(&[1, 5, 12, 17]);
assert_eq!(peek_size(&buf), buf.len() - 4); assert_eq!(peek_size(&buf), buf.len() - 4);
} }
#[test] #[test]
fn peek_2() { fn peek_2() {
use super::peek_size; use super::peek_size;
let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized"); let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
let mut buf = serialize(module).expect("serialization to succeed"); let mut buf = serialize(module).expect("serialization to succeed");
buf.extend_from_slice(&[0, 0, 0, 0, 0, 1, 5, 12, 17]); buf.extend_from_slice(&[0, 0, 0, 0, 0, 1, 5, 12, 17]);
assert_eq!(peek_size(&buf), buf.len() - 9); assert_eq!(peek_size(&buf), buf.len() - 9);
} }
#[test] #[test]
fn module_default_round_trip() { fn module_default_round_trip() {
let module1 = Module::default(); let module1 = Module::default();
let buf = serialize(module1).expect("Serialization should succeed"); let buf = serialize(module1).expect("Serialization should succeed");
let module2: Module = deserialize_buffer(&buf).expect("Deserialization should succeed"); let module2: Module = deserialize_buffer(&buf).expect("Deserialization should succeed");
assert_eq!(Module::default().magic, module2.magic); assert_eq!(Module::default().magic, module2.magic);
} }
#[test] #[test]
fn names() { fn names() {
use super::super::name_section::NameSection; use super::super::name_section::NameSection;
let module = deserialize_file("./res/cases/v1/with_names.wasm") let module = deserialize_file("./res/cases/v1/with_names.wasm")
.expect("Should be deserialized") .expect("Should be deserialized")
.parse_names() .parse_names()
.expect("Names to be parsed"); .expect("Names to be parsed");
let mut found_section = false; let mut found_section = false;
for section in module.sections() { for section in module.sections() {
match *section { match *section {
Section::Name(ref name_section) => { Section::Name(ref name_section) => {
match *name_section { match *name_section {
NameSection::Function(ref function_name_section) => { NameSection::Function(ref function_name_section) => {
assert_eq!( assert_eq!(
function_name_section.names().get(0).expect("Should be entry #0"), function_name_section.names().get(0).expect("Should be entry #0"),
"elog" "elog"
); );
assert_eq!( assert_eq!(
function_name_section.names().get(11).expect("Should be entry #0"), function_name_section.names().get(11).expect("Should be entry #0"),
"_ZN48_$LT$pwasm_token_contract..Endpoint$LT$T$GT$$GT$3new17hc3ace6dea0978cd9E" "_ZN48_$LT$pwasm_token_contract..Endpoint$LT$T$GT$$GT$3new17hc3ace6dea0978cd9E"
); );
found_section = true; found_section = true;
}, },
_ => {}, _ => {},
} }
}, },
_ => {}, _ => {},
} }
} }
assert!(found_section, "Name section should be present in dedicated example"); assert!(found_section, "Name section should be present in dedicated example");
} }
} }

View File

@ -10,218 +10,218 @@ const NAME_TYPE_LOCAL: u8 = 2;
/// Debug name information. /// Debug name information.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum NameSection { pub enum NameSection {
/// Module name section. /// Module name section.
Module(ModuleNameSection), Module(ModuleNameSection),
/// Function name section. /// Function name section.
Function(FunctionNameSection), Function(FunctionNameSection),
/// Local name section. /// Local name section.
Local(LocalNameSection), Local(LocalNameSection),
/// Name section is unparsed. /// Name section is unparsed.
Unparsed { Unparsed {
/// The numeric identifier for this name section type. /// The numeric identifier for this name section type.
name_type: u8, name_type: u8,
/// The contents of this name section, unparsed. /// The contents of this name section, unparsed.
name_payload: Vec<u8>, name_payload: Vec<u8>,
}, },
} }
impl NameSection { impl NameSection {
/// Deserialize a name section. /// Deserialize a name section.
pub fn deserialize<R: Read>( pub fn deserialize<R: Read>(
module: &Module, module: &Module,
rdr: &mut R, rdr: &mut R,
) -> Result<NameSection, Error> { ) -> Result<NameSection, Error> {
let name_type: u8 = VarUint7::deserialize(rdr)?.into(); let name_type: u8 = VarUint7::deserialize(rdr)?.into();
let name_payload_len: u32 = VarUint32::deserialize(rdr)?.into(); let name_payload_len: u32 = VarUint32::deserialize(rdr)?.into();
let name_section = match name_type { let name_section = match name_type {
NAME_TYPE_MODULE => NameSection::Module(ModuleNameSection::deserialize(rdr)?), NAME_TYPE_MODULE => NameSection::Module(ModuleNameSection::deserialize(rdr)?),
NAME_TYPE_FUNCTION => NameSection::Function(FunctionNameSection::deserialize(module, rdr)?), NAME_TYPE_FUNCTION => NameSection::Function(FunctionNameSection::deserialize(module, rdr)?),
NAME_TYPE_LOCAL => NameSection::Local(LocalNameSection::deserialize(module, rdr)?), NAME_TYPE_LOCAL => NameSection::Local(LocalNameSection::deserialize(module, rdr)?),
_ => { _ => {
let mut name_payload = vec![0u8; name_payload_len as usize]; let mut name_payload = vec![0u8; name_payload_len as usize];
rdr.read_exact(&mut name_payload)?; rdr.read_exact(&mut name_payload)?;
NameSection::Unparsed { NameSection::Unparsed {
name_type, name_type,
name_payload, name_payload,
} }
} }
}; };
Ok(name_section) Ok(name_section)
} }
} }
impl Serialize for NameSection { impl Serialize for NameSection {
type Error = Error; type Error = Error;
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> { fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
let (name_type, name_payload) = match self { let (name_type, name_payload) = match self {
NameSection::Module(mod_name) => { NameSection::Module(mod_name) => {
let mut buffer = vec![]; let mut buffer = vec![];
mod_name.serialize(&mut buffer)?; mod_name.serialize(&mut buffer)?;
(NAME_TYPE_MODULE, buffer) (NAME_TYPE_MODULE, buffer)
} }
NameSection::Function(fn_names) => { NameSection::Function(fn_names) => {
let mut buffer = vec![]; let mut buffer = vec![];
fn_names.serialize(&mut buffer)?; fn_names.serialize(&mut buffer)?;
(NAME_TYPE_FUNCTION, buffer) (NAME_TYPE_FUNCTION, buffer)
} }
NameSection::Local(local_names) => { NameSection::Local(local_names) => {
let mut buffer = vec![]; let mut buffer = vec![];
local_names.serialize(&mut buffer)?; local_names.serialize(&mut buffer)?;
(NAME_TYPE_LOCAL, buffer) (NAME_TYPE_LOCAL, buffer)
} }
NameSection::Unparsed { NameSection::Unparsed {
name_type, name_type,
name_payload, name_payload,
} => (name_type, name_payload), } => (name_type, name_payload),
}; };
VarUint7::from(name_type).serialize(wtr)?; VarUint7::from(name_type).serialize(wtr)?;
VarUint32::from(name_payload.len()).serialize(wtr)?; VarUint32::from(name_payload.len()).serialize(wtr)?;
wtr.write_all(&name_payload)?; wtr.write_all(&name_payload)?;
Ok(()) Ok(())
} }
} }
/// The name of this module. /// The name of this module.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ModuleNameSection { pub struct ModuleNameSection {
name: String, name: String,
} }
impl ModuleNameSection { impl ModuleNameSection {
/// Create a new module name section with the specified name. /// Create a new module name section with the specified name.
pub fn new<S: Into<String>>(name: S) -> ModuleNameSection { pub fn new<S: Into<String>>(name: S) -> ModuleNameSection {
ModuleNameSection { name: name.into() } ModuleNameSection { name: name.into() }
} }
/// The name of this module. /// The name of this module.
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
&self.name &self.name
} }
/// The name of this module (mutable). /// The name of this module (mutable).
pub fn name_mut(&mut self) -> &mut String { pub fn name_mut(&mut self) -> &mut String {
&mut self.name &mut self.name
} }
} }
impl Serialize for ModuleNameSection { impl Serialize for ModuleNameSection {
type Error = Error; type Error = Error;
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> { fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
self.name.serialize(wtr) self.name.serialize(wtr)
} }
} }
impl Deserialize for ModuleNameSection { impl Deserialize for ModuleNameSection {
type Error = Error; type Error = Error;
fn deserialize<R: Read>(rdr: &mut R) -> Result<ModuleNameSection, Error> { fn deserialize<R: Read>(rdr: &mut R) -> Result<ModuleNameSection, Error> {
let name = String::deserialize(rdr)?; let name = String::deserialize(rdr)?;
Ok(ModuleNameSection { name }) Ok(ModuleNameSection { name })
} }
} }
/// The names of the functions in this module. /// The names of the functions in this module.
#[derive(Clone, Debug, Default, PartialEq)] #[derive(Clone, Debug, Default, PartialEq)]
pub struct FunctionNameSection { pub struct FunctionNameSection {
names: NameMap, names: NameMap,
} }
impl FunctionNameSection { impl FunctionNameSection {
/// A map from function indices to names. /// A map from function indices to names.
pub fn names(&self) -> &NameMap { pub fn names(&self) -> &NameMap {
&self.names &self.names
} }
/// A map from function indices to names (mutable). /// A map from function indices to names (mutable).
pub fn names_mut(&mut self) -> &mut NameMap { pub fn names_mut(&mut self) -> &mut NameMap {
&mut self.names &mut self.names
} }
/// Deserialize names, making sure that all names correspond to functions. /// Deserialize names, making sure that all names correspond to functions.
pub fn deserialize<R: Read>( pub fn deserialize<R: Read>(
module: &Module, module: &Module,
rdr: &mut R, rdr: &mut R,
) -> Result<FunctionNameSection, Error> { ) -> Result<FunctionNameSection, Error> {
let names = IndexMap::deserialize(module.functions_space(), rdr)?; let names = IndexMap::deserialize(module.functions_space(), rdr)?;
Ok(FunctionNameSection { names }) Ok(FunctionNameSection { names })
} }
} }
impl Serialize for FunctionNameSection { impl Serialize for FunctionNameSection {
type Error = Error; type Error = Error;
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> { fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
self.names.serialize(wtr) self.names.serialize(wtr)
} }
} }
/// The names of the local variables in this module's functions. /// The names of the local variables in this module's functions.
#[derive(Clone, Debug, Default, PartialEq)] #[derive(Clone, Debug, Default, PartialEq)]
pub struct LocalNameSection { pub struct LocalNameSection {
local_names: IndexMap<NameMap>, local_names: IndexMap<NameMap>,
} }
impl LocalNameSection { impl LocalNameSection {
/// A map from function indices to a map from variables indices to names. /// A map from function indices to a map from variables indices to names.
pub fn local_names(&self) -> &IndexMap<NameMap> { pub fn local_names(&self) -> &IndexMap<NameMap> {
&self.local_names &self.local_names
} }
/// A map from function indices to a map from variables indices to names /// A map from function indices to a map from variables indices to names
/// (mutable). /// (mutable).
pub fn local_names_mut(&mut self) -> &mut IndexMap<NameMap> { pub fn local_names_mut(&mut self) -> &mut IndexMap<NameMap> {
&mut self.local_names &mut self.local_names
} }
/// Deserialize names, making sure that all names correspond to local /// Deserialize names, making sure that all names correspond to local
/// variables. /// variables.
pub fn deserialize<R: Read>( pub fn deserialize<R: Read>(
module: &Module, module: &Module,
rdr: &mut R, rdr: &mut R,
) -> Result<LocalNameSection, Error> { ) -> Result<LocalNameSection, Error> {
let funcs = module.function_section().ok_or_else(|| { let funcs = module.function_section().ok_or_else(|| {
Error::Other("cannot deserialize local names without a function section") Error::Other("cannot deserialize local names without a function section")
})?; })?;
let max_entry_space = funcs.entries().len(); let max_entry_space = funcs.entries().len();
let max_signature_args = module let max_signature_args = module
.type_section() .type_section()
.map(|ts| .map(|ts|
ts.types() ts.types()
.iter() .iter()
.map(|x| { let Type::Function(ref func) = *x; func.params().len() }) .map(|x| { let Type::Function(ref func) = *x; func.params().len() })
.max() .max()
.unwrap_or(0)) .unwrap_or(0))
.unwrap_or(0); .unwrap_or(0);
let max_locals = module let max_locals = module
.code_section() .code_section()
.map(|cs| cs.bodies().iter().map(|f| f.locals().len()).max().unwrap_or(0)) .map(|cs| cs.bodies().iter().map(|f| f.locals().len()).max().unwrap_or(0))
.unwrap_or(0); .unwrap_or(0);
let max_space = max_signature_args + max_locals; let max_space = max_signature_args + max_locals;
let deserialize_locals = |_: u32, rdr: &mut R| IndexMap::deserialize(max_space, rdr); let deserialize_locals = |_: u32, rdr: &mut R| IndexMap::deserialize(max_space, rdr);
let local_names = IndexMap::deserialize_with( let local_names = IndexMap::deserialize_with(
max_entry_space, max_entry_space,
&deserialize_locals, &deserialize_locals,
rdr, rdr,
)?; )?;
Ok(LocalNameSection { local_names }) Ok(LocalNameSection { local_names })
}} }}
impl Serialize for LocalNameSection { impl Serialize for LocalNameSection {
type Error = Error; type Error = Error;
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> { fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
self.local_names.serialize(wtr) self.local_names.serialize(wtr)
} }
} }
/// A map from indices to names. /// A map from indices to names.
@ -229,48 +229,48 @@ pub type NameMap = IndexMap<String>;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
// A helper funtion for the tests. Serialize a section, deserialize it, // A helper funtion for the tests. Serialize a section, deserialize it,
// and make sure it matches the original. // and make sure it matches the original.
fn serialize_test(original: NameSection) -> Vec<u8> { fn serialize_test(original: NameSection) -> Vec<u8> {
let mut buffer = vec![]; let mut buffer = vec![];
original original
.serialize(&mut buffer) .serialize(&mut buffer)
.expect("serialize error"); .expect("serialize error");
buffer buffer
} }
#[test] #[test]
fn serialize_module_name() { fn serialize_module_name() {
let original = NameSection::Module(ModuleNameSection::new("my_mod")); let original = NameSection::Module(ModuleNameSection::new("my_mod"));
serialize_test(original.clone()); serialize_test(original.clone());
} }
#[test] #[test]
fn serialize_function_names() { fn serialize_function_names() {
let mut sect = FunctionNameSection::default(); let mut sect = FunctionNameSection::default();
sect.names_mut().insert(0, "hello_world".to_string()); sect.names_mut().insert(0, "hello_world".to_string());
serialize_test(NameSection::Function(sect)); serialize_test(NameSection::Function(sect));
} }
#[test] #[test]
fn serialize_local_names() { fn serialize_local_names() {
let mut sect = LocalNameSection::default(); let mut sect = LocalNameSection::default();
let mut locals = NameMap::default(); let mut locals = NameMap::default();
locals.insert(0, "msg".to_string()); locals.insert(0, "msg".to_string());
sect.local_names_mut().insert(0, locals); sect.local_names_mut().insert(0, locals);
serialize_test(NameSection::Local(sect)); serialize_test(NameSection::Local(sect));
} }
#[test] #[test]
fn serialize_and_deserialize_unparsed() { fn serialize_and_deserialize_unparsed() {
let original = NameSection::Unparsed { let original = NameSection::Unparsed {
// A made-up name section type which is unlikely to be allocated // A made-up name section type which is unlikely to be allocated
// soon, in order to allow us to test `Unparsed`. // soon, in order to allow us to test `Unparsed`.
name_type: 120, name_type: 120,
name_payload: vec![0u8, 1, 2], name_payload: vec![0u8, 1, 2],
}; };
serialize_test(original.clone()); serialize_test(original.clone());
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,132 +4,132 @@ use super::{Deserialize, Serialize, Error, VarUint32, CountedList, InitExpr, Cou
/// Entry in the element section. /// Entry in the element section.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ElementSegment { pub struct ElementSegment {
index: u32, index: u32,
offset: InitExpr, offset: InitExpr,
members: Vec<u32>, members: Vec<u32>,
} }
impl ElementSegment { impl ElementSegment {
/// New element segment. /// New element segment.
pub fn new(index: u32, offset: InitExpr, members: Vec<u32>) -> Self { pub fn new(index: u32, offset: InitExpr, members: Vec<u32>) -> Self {
ElementSegment { index: index, offset: offset, members: members } ElementSegment { index: index, offset: offset, members: members }
} }
/// Sequence of function indices. /// Sequence of function indices.
pub fn members(&self) -> &[u32] { &self.members } pub fn members(&self) -> &[u32] { &self.members }
/// Sequence of function indices (mutable) /// Sequence of function indices (mutable)
pub fn members_mut(&mut self) -> &mut Vec<u32> { &mut self.members } pub fn members_mut(&mut self) -> &mut Vec<u32> { &mut self.members }
/// Table index (currently valid only value of `0`) /// Table index (currently valid only value of `0`)
pub fn index(&self) -> u32 { self.index } pub fn index(&self) -> u32 { self.index }
/// An i32 initializer expression that computes the offset at which to place the elements. /// An i32 initializer expression that computes the offset at which to place the elements.
pub fn offset(&self) -> &InitExpr { &self.offset } pub fn offset(&self) -> &InitExpr { &self.offset }
/// An i32 initializer expression that computes the offset at which to place the elements (mutable) /// An i32 initializer expression that computes the offset at which to place the elements (mutable)
pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset } pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset }
} }
impl Deserialize for ElementSegment { impl Deserialize for ElementSegment {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let index = VarUint32::deserialize(reader)?; let index = VarUint32::deserialize(reader)?;
let offset = InitExpr::deserialize(reader)?; let offset = InitExpr::deserialize(reader)?;
let funcs: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)? let funcs: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
.into_inner() .into_inner()
.into_iter() .into_iter()
.map(Into::into) .map(Into::into)
.collect(); .collect();
Ok(ElementSegment { Ok(ElementSegment {
index: index.into(), index: index.into(),
offset: offset, offset: offset,
members: funcs, members: funcs,
}) })
} }
} }
impl Serialize for ElementSegment { impl Serialize for ElementSegment {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
VarUint32::from(self.index).serialize(writer)?; VarUint32::from(self.index).serialize(writer)?;
self.offset.serialize(writer)?; self.offset.serialize(writer)?;
let data = self.members; let data = self.members;
let counted_list = CountedListWriter::<VarUint32, _>( let counted_list = CountedListWriter::<VarUint32, _>(
data.len(), data.len(),
data.into_iter().map(Into::into), data.into_iter().map(Into::into),
); );
counted_list.serialize(writer)?; counted_list.serialize(writer)?;
Ok(()) Ok(())
} }
} }
/// Data segment definition. /// Data segment definition.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DataSegment { pub struct DataSegment {
index: u32, index: u32,
offset: InitExpr, offset: InitExpr,
value: Vec<u8>, value: Vec<u8>,
} }
impl DataSegment { impl DataSegment {
/// New data segments. /// New data segments.
pub fn new(index: u32, offset: InitExpr, value: Vec<u8>) -> Self { pub fn new(index: u32, offset: InitExpr, value: Vec<u8>) -> Self {
DataSegment { DataSegment {
index: index, index: index,
offset: offset, offset: offset,
value: value, value: value,
} }
} }
/// Linear memory index (currently the only valid value is `0`). /// Linear memory index (currently the only valid value is `0`).
pub fn index(&self) -> u32 { self.index } pub fn index(&self) -> u32 { self.index }
/// An i32 initializer expression that computes the offset at which to place the data. /// An i32 initializer expression that computes the offset at which to place the data.
pub fn offset(&self) -> &InitExpr { &self.offset } pub fn offset(&self) -> &InitExpr { &self.offset }
/// An i32 initializer expression that computes the offset at which to place the data (mutable) /// An i32 initializer expression that computes the offset at which to place the data (mutable)
pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset } pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset }
/// Initial value of the data segment. /// Initial value of the data segment.
pub fn value(&self) -> &[u8] { &self.value } pub fn value(&self) -> &[u8] { &self.value }
/// Initial value of the data segment (mutable). /// Initial value of the data segment (mutable).
pub fn value_mut(&mut self) -> &mut Vec<u8> { &mut self.value } pub fn value_mut(&mut self) -> &mut Vec<u8> { &mut self.value }
} }
impl Deserialize for DataSegment { impl Deserialize for DataSegment {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let index = VarUint32::deserialize(reader)?; let index = VarUint32::deserialize(reader)?;
let offset = InitExpr::deserialize(reader)?; let offset = InitExpr::deserialize(reader)?;
let value_len = VarUint32::deserialize(reader)?; let value_len = VarUint32::deserialize(reader)?;
let mut value_buf = vec![0u8; value_len.into()]; let mut value_buf = vec![0u8; value_len.into()];
reader.read_exact(&mut value_buf[..])?; reader.read_exact(&mut value_buf[..])?;
Ok(DataSegment { Ok(DataSegment {
index: index.into(), index: index.into(),
offset: offset, offset: offset,
value: value_buf, value: value_buf,
}) })
} }
} }
impl Serialize for DataSegment { impl Serialize for DataSegment {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
VarUint32::from(self.index).serialize(writer)?; VarUint32::from(self.index).serialize(writer)?;
self.offset.serialize(writer)?; self.offset.serialize(writer)?;
let value = self.value; let value = self.value;
VarUint32::from(value.len()).serialize(writer)?; VarUint32::from(value.len()).serialize(writer)?;
writer.write_all(&value[..])?; writer.write_all(&value[..])?;
Ok(()) Ok(())
} }
} }

View File

@ -1,245 +1,245 @@
use std::{io, fmt}; use std::{io, fmt};
use super::{ use super::{
Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint1, CountedList, Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint1, CountedList,
CountedListWriter CountedListWriter
}; };
/// Type definition in types section. Currently can be only of the function type. /// Type definition in types section. Currently can be only of the function type.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum Type { pub enum Type {
/// Function type. /// Function type.
Function(FunctionType), Function(FunctionType),
} }
impl Deserialize for Type { impl Deserialize for Type {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
Ok(Type::Function(FunctionType::deserialize(reader)?)) Ok(Type::Function(FunctionType::deserialize(reader)?))
} }
} }
impl Serialize for Type { impl Serialize for Type {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
match self { match self {
Type::Function(fn_type) => fn_type.serialize(writer) Type::Function(fn_type) => fn_type.serialize(writer)
} }
} }
} }
/// Value type. /// Value type.
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Debug)]
pub enum ValueType { pub enum ValueType {
/// 32-bit signed integer /// 32-bit signed integer
I32, I32,
/// 64-bit signed integer /// 64-bit signed integer
I64, I64,
/// 32-bit float /// 32-bit float
F32, F32,
/// 64-bit float /// 64-bit float
F64, F64,
} }
impl Deserialize for ValueType { impl Deserialize for ValueType {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let val = VarInt7::deserialize(reader)?; let val = VarInt7::deserialize(reader)?;
match val.into() { match val.into() {
-0x01 => Ok(ValueType::I32), -0x01 => Ok(ValueType::I32),
-0x02 => Ok(ValueType::I64), -0x02 => Ok(ValueType::I64),
-0x03 => Ok(ValueType::F32), -0x03 => Ok(ValueType::F32),
-0x04 => Ok(ValueType::F64), -0x04 => Ok(ValueType::F64),
_ => Err(Error::UnknownValueType(val.into())), _ => Err(Error::UnknownValueType(val.into())),
} }
} }
} }
impl Serialize for ValueType { impl Serialize for ValueType {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
let val: VarInt7 = match self { let val: VarInt7 = match self {
ValueType::I32 => -0x01, ValueType::I32 => -0x01,
ValueType::I64 => -0x02, ValueType::I64 => -0x02,
ValueType::F32 => -0x03, ValueType::F32 => -0x03,
ValueType::F64 => -0x04, ValueType::F64 => -0x04,
}.into(); }.into();
val.serialize(writer)?; val.serialize(writer)?;
Ok(()) Ok(())
} }
} }
impl fmt::Display for ValueType { impl fmt::Display for ValueType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
ValueType::I32 => write!(f, "i32"), ValueType::I32 => write!(f, "i32"),
ValueType::I64 => write!(f, "i64"), ValueType::I64 => write!(f, "i64"),
ValueType::F32 => write!(f, "f32"), ValueType::F32 => write!(f, "f32"),
ValueType::F64 => write!(f, "f64"), ValueType::F64 => write!(f, "f64"),
} }
} }
} }
/// Block type which is basically `ValueType` + NoResult (to define blocks that have no return type) /// Block type which is basically `ValueType` + NoResult (to define blocks that have no return type)
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Debug)]
pub enum BlockType { pub enum BlockType {
/// Value-type specified block type /// Value-type specified block type
Value(ValueType), Value(ValueType),
/// No specified block type /// No specified block type
NoResult, NoResult,
} }
impl Deserialize for BlockType { impl Deserialize for BlockType {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let val = VarInt7::deserialize(reader)?; let val = VarInt7::deserialize(reader)?;
match val.into() { match val.into() {
-0x01 => Ok(BlockType::Value(ValueType::I32)), -0x01 => Ok(BlockType::Value(ValueType::I32)),
-0x02 => Ok(BlockType::Value(ValueType::I64)), -0x02 => Ok(BlockType::Value(ValueType::I64)),
-0x03 => Ok(BlockType::Value(ValueType::F32)), -0x03 => Ok(BlockType::Value(ValueType::F32)),
-0x04 => Ok(BlockType::Value(ValueType::F64)), -0x04 => Ok(BlockType::Value(ValueType::F64)),
-0x40 => Ok(BlockType::NoResult), -0x40 => Ok(BlockType::NoResult),
_ => Err(Error::UnknownValueType(val.into())), _ => Err(Error::UnknownValueType(val.into())),
} }
} }
} }
impl Serialize for BlockType { impl Serialize for BlockType {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
let val: VarInt7 = match self { let val: VarInt7 = match self {
BlockType::NoResult => -0x40i8, BlockType::NoResult => -0x40i8,
BlockType::Value(ValueType::I32) => -0x01, BlockType::Value(ValueType::I32) => -0x01,
BlockType::Value(ValueType::I64) => -0x02, BlockType::Value(ValueType::I64) => -0x02,
BlockType::Value(ValueType::F32) => -0x03, BlockType::Value(ValueType::F32) => -0x03,
BlockType::Value(ValueType::F64) => -0x04, BlockType::Value(ValueType::F64) => -0x04,
}.into(); }.into();
val.serialize(writer)?; val.serialize(writer)?;
Ok(()) Ok(())
} }
} }
/// Function signature type. /// Function signature type.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct FunctionType { pub struct FunctionType {
form: u8, form: u8,
params: Vec<ValueType>, params: Vec<ValueType>,
return_type: Option<ValueType>, return_type: Option<ValueType>,
} }
impl Default for FunctionType { impl Default for FunctionType {
fn default() -> Self { fn default() -> Self {
FunctionType { FunctionType {
form: 0x60, form: 0x60,
params: Vec::new(), params: Vec::new(),
return_type: None, return_type: None,
} }
} }
} }
impl FunctionType { impl FunctionType {
/// New function type given the signature in-params(`params`) and return type (`return_type`) /// New function type given the signature in-params(`params`) and return type (`return_type`)
pub fn new(params: Vec<ValueType>, return_type: Option<ValueType>) -> Self { pub fn new(params: Vec<ValueType>, return_type: Option<ValueType>) -> Self {
FunctionType { FunctionType {
params: params, params: params,
return_type: return_type, return_type: return_type,
..Default::default() ..Default::default()
} }
} }
/// Function form (currently only valid value is `0x60`) /// Function form (currently only valid value is `0x60`)
pub fn form(&self) -> u8 { self.form } pub fn form(&self) -> u8 { self.form }
/// Parameters in the function signature. /// Parameters in the function signature.
pub fn params(&self) -> &[ValueType] { &self.params } pub fn params(&self) -> &[ValueType] { &self.params }
/// Mutable parameters in the function signature. /// Mutable parameters in the function signature.
pub fn params_mut(&mut self) -> &mut Vec<ValueType> { &mut self.params } pub fn params_mut(&mut self) -> &mut Vec<ValueType> { &mut self.params }
/// Return type in the function signature, if any. /// Return type in the function signature, if any.
pub fn return_type(&self) -> Option<ValueType> { self.return_type } pub fn return_type(&self) -> Option<ValueType> { self.return_type }
/// Mutable type in the function signature, if any. /// Mutable type in the function signature, if any.
pub fn return_type_mut(&mut self) -> &mut Option<ValueType> { &mut self.return_type } pub fn return_type_mut(&mut self) -> &mut Option<ValueType> { &mut self.return_type }
} }
impl Deserialize for FunctionType { impl Deserialize for FunctionType {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let form: u8 = VarUint7::deserialize(reader)?.into(); let form: u8 = VarUint7::deserialize(reader)?.into();
let params: Vec<ValueType> = CountedList::deserialize(reader)?.into_inner(); let params: Vec<ValueType> = CountedList::deserialize(reader)?.into_inner();
let has_return_type = VarUint1::deserialize(reader)?; let has_return_type = VarUint1::deserialize(reader)?;
let return_type = if has_return_type.into() { let return_type = if has_return_type.into() {
Some(ValueType::deserialize(reader)?) Some(ValueType::deserialize(reader)?)
} else { } else {
None None
}; };
Ok(FunctionType { Ok(FunctionType {
form: form, form: form,
params: params, params: params,
return_type: return_type, return_type: return_type,
}) })
} }
} }
impl Serialize for FunctionType { impl Serialize for FunctionType {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
VarUint7::from(self.form).serialize(writer)?; VarUint7::from(self.form).serialize(writer)?;
let data = self.params; let data = self.params;
let counted_list = CountedListWriter::<ValueType, _>( let counted_list = CountedListWriter::<ValueType, _>(
data.len(), data.len(),
data.into_iter().map(Into::into), data.into_iter().map(Into::into),
); );
counted_list.serialize(writer)?; counted_list.serialize(writer)?;
if let Some(return_type) = self.return_type { if let Some(return_type) = self.return_type {
VarUint1::from(true).serialize(writer)?; VarUint1::from(true).serialize(writer)?;
return_type.serialize(writer)?; return_type.serialize(writer)?;
} else { } else {
VarUint1::from(false).serialize(writer)?; VarUint1::from(false).serialize(writer)?;
} }
Ok(()) Ok(())
} }
} }
/// Table element type. /// Table element type.
#[derive(Clone, Copy, PartialEq, Debug)] #[derive(Clone, Copy, PartialEq, Debug)]
pub enum TableElementType { pub enum TableElementType {
/// A reference to a function with any signature. /// A reference to a function with any signature.
AnyFunc, AnyFunc,
} }
impl Deserialize for TableElementType { impl Deserialize for TableElementType {
type Error = Error; type Error = Error;
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> { fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
let val = VarInt7::deserialize(reader)?; let val = VarInt7::deserialize(reader)?;
match val.into() { match val.into() {
-0x10 => Ok(TableElementType::AnyFunc), -0x10 => Ok(TableElementType::AnyFunc),
_ => Err(Error::UnknownTableElementType(val.into())), _ => Err(Error::UnknownTableElementType(val.into())),
} }
} }
} }
impl Serialize for TableElementType { impl Serialize for TableElementType {
type Error = Error; type Error = Error;
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> { fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
let val: VarInt7 = match self { let val: VarInt7 = match self {
TableElementType::AnyFunc => 0x70, TableElementType::AnyFunc => 0x70,
}.into(); }.into();
val.serialize(writer)?; val.serialize(writer)?;
Ok(()) Ok(())
} }
} }

View File

@ -14,18 +14,18 @@ mod validation;
mod common; mod common;
pub use elements::{ pub use elements::{
Error as SerializationError, Error as SerializationError,
deserialize_buffer, deserialize_buffer,
deserialize_file, deserialize_file,
serialize, serialize,
serialize_to_file, serialize_to_file,
peek_size, peek_size,
}; };
#[allow(deprecated)] #[allow(deprecated)]
pub use interpreter::{ pub use interpreter::{
ProgramInstance, ProgramInstance,
ModuleInstance, ModuleInstance,
ModuleInstanceInterface, ModuleInstanceInterface,
RuntimeValue, RuntimeValue,
}; };