mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-27 13:41:58 +00:00
spaces to tabs
This commit is contained in:
@ -11,37 +11,37 @@ use parity_wasm::elements;
|
||||
|
||||
fn main() {
|
||||
|
||||
// Example binary accepts one parameter which is the output file
|
||||
// where generated wasm module will be written at the end of execution
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 2 {
|
||||
println!("Usage: {} output_file.wasm", args[0]);
|
||||
return;
|
||||
}
|
||||
// Example binary accepts one parameter which is the output file
|
||||
// where generated wasm module will be written at the end of execution
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 2 {
|
||||
println!("Usage: {} output_file.wasm", args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Main entry for the builder api is the module function
|
||||
// It returns empty module builder structure which can be further
|
||||
// appended with various wasm artefacts
|
||||
let module = builder::module()
|
||||
// Here we append function to the builder
|
||||
// function() function returns a function builder attached
|
||||
// to the module builder.
|
||||
.function()
|
||||
// We describe signature for the function via signature()
|
||||
// function. In our simple example it's just one input
|
||||
// argument of type 'i32' without return value
|
||||
.signature().with_param(elements::ValueType::I32).build()
|
||||
// body() without any further arguments means that the body
|
||||
// of the function will be empty
|
||||
.body().build()
|
||||
// This is the end of the function builder. When `build()` is
|
||||
// invoked, function builder returns original module builder
|
||||
// from which it was invoked
|
||||
.build()
|
||||
// And finally we finish our module builder to produce actual
|
||||
// wasm module.
|
||||
.build();
|
||||
// Main entry for the builder api is the module function
|
||||
// It returns empty module builder structure which can be further
|
||||
// appended with various wasm artefacts
|
||||
let module = builder::module()
|
||||
// Here we append function to the builder
|
||||
// function() function returns a function builder attached
|
||||
// to the module builder.
|
||||
.function()
|
||||
// We describe signature for the function via signature()
|
||||
// function. In our simple example it's just one input
|
||||
// argument of type 'i32' without return value
|
||||
.signature().with_param(elements::ValueType::I32).build()
|
||||
// body() without any further arguments means that the body
|
||||
// of the function will be empty
|
||||
.body().build()
|
||||
// This is the end of the function builder. When `build()` is
|
||||
// invoked, function builder returns original module builder
|
||||
// from which it was invoked
|
||||
.build()
|
||||
// And finally we finish our module builder to produce actual
|
||||
// wasm module.
|
||||
.build();
|
||||
|
||||
// Module structure can be serialzed to produce a valid wasm file
|
||||
parity_wasm::serialize_to_file(&args[1], module).unwrap();
|
||||
// Module structure can be serialzed to produce a valid wasm file
|
||||
parity_wasm::serialize_to_file(&args[1], module).unwrap();
|
||||
}
|
@ -7,40 +7,40 @@ use std::env;
|
||||
|
||||
fn main() {
|
||||
|
||||
// Example executable takes one argument which must
|
||||
// refernce the existing file with a valid wasm module
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 2 {
|
||||
println!("Usage: {} somefile.wasm", args[0]);
|
||||
return;
|
||||
}
|
||||
// Example executable takes one argument which must
|
||||
// refernce the existing file with a valid wasm module
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 2 {
|
||||
println!("Usage: {} somefile.wasm", args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Here we load module using dedicated for this purpose
|
||||
// `deserialize_file` function (which works only with modules)
|
||||
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
||||
// Here we load module using dedicated for this purpose
|
||||
// `deserialize_file` function (which works only with modules)
|
||||
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
||||
|
||||
// We query module for data section. Note that not every valid
|
||||
// wasm module must contain a data section. So in case the provided
|
||||
// module does not contain data section, we panic with an error
|
||||
let data_section = module.data_section().expect("no data section in module");
|
||||
// We query module for data section. Note that not every valid
|
||||
// wasm module must contain a data section. So in case the provided
|
||||
// module does not contain data section, we panic with an error
|
||||
let data_section = module.data_section().expect("no data section in module");
|
||||
|
||||
// Printing the total count of data segments
|
||||
println!("Data segments: {}", data_section.entries().len());
|
||||
// Printing the total count of data segments
|
||||
println!("Data segments: {}", data_section.entries().len());
|
||||
|
||||
let mut index = 0;
|
||||
for entry in data_section.entries() {
|
||||
// Printing the details info of each data segment
|
||||
// see `elements::DataSegment` for more properties
|
||||
// you can query
|
||||
println!(" Entry #{}", index);
|
||||
let mut index = 0;
|
||||
for entry in data_section.entries() {
|
||||
// Printing the details info of each data segment
|
||||
// see `elements::DataSegment` for more properties
|
||||
// you can query
|
||||
println!(" Entry #{}", index);
|
||||
|
||||
// This shows the initialization member of data segment
|
||||
// (expression which must resolve in the linear memory location).
|
||||
println!(" init: {}", entry.offset().code()[0]);
|
||||
// This shows the initialization member of data segment
|
||||
// (expression which must resolve in the linear memory location).
|
||||
println!(" init: {}", entry.offset().code()[0]);
|
||||
|
||||
// This shows the total length of the data segment in bytes.
|
||||
println!(" size: {}", entry.value().len());
|
||||
// This shows the total length of the data segment in bytes.
|
||||
println!(" size: {}", entry.value().len());
|
||||
|
||||
index += 1;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
@ -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
|
||||
fn type_by_index(module: &Module, index: usize) -> FunctionType {
|
||||
|
||||
// Demand that function and type section exist. Otherwise, fail with a
|
||||
// corresponding error.
|
||||
let function_section = module.function_section().expect("No function section found");
|
||||
let type_section = module.type_section().expect("No type section found");
|
||||
// Demand that function and type section exist. Otherwise, fail with a
|
||||
// corresponding error.
|
||||
let function_section = module.function_section().expect("No function 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
|
||||
// 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
|
||||
// to resolve actual index of the given function in own functions list.
|
||||
let import_section_len: usize = match module.import_section() {
|
||||
Some(import) =>
|
||||
import.entries().iter().filter(|entry| match entry.external() {
|
||||
&External::Function(_) => true,
|
||||
_ => false,
|
||||
}).count(),
|
||||
None => 0,
|
||||
};
|
||||
// This counts the number of _function_ imports listed by the module, excluding
|
||||
// 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
|
||||
// to resolve actual index of the given function in own functions list.
|
||||
let import_section_len: usize = match module.import_section() {
|
||||
Some(import) =>
|
||||
import.entries().iter().filter(|entry| match entry.external() {
|
||||
&External::Function(_) => true,
|
||||
_ => false,
|
||||
}).count(),
|
||||
None => 0,
|
||||
};
|
||||
|
||||
// Substract the value queried in the previous step from the provided index
|
||||
// to get own function index from which we can query type next.
|
||||
let function_index_in_section = index - import_section_len;
|
||||
// Substract the value queried in the previous step from the provided index
|
||||
// to get own function index from which we can query type next.
|
||||
let function_index_in_section = index - import_section_len;
|
||||
|
||||
// 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;
|
||||
// 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;
|
||||
|
||||
// Finally, return function type (signature)
|
||||
match type_section.types()[func_type_ref] {
|
||||
Type::Function(ref func_type) => func_type.clone(),
|
||||
}
|
||||
// Finally, return function type (signature)
|
||||
match type_section.types()[func_type_ref] {
|
||||
Type::Function(ref func_type) => func_type.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
// Example executable takes one argument which must
|
||||
// refernce the existing file with a valid wasm module
|
||||
let args: Vec<_> = args().collect();
|
||||
if args.len() < 2 {
|
||||
println!("Prints export function names with and their types");
|
||||
println!("Usage: {} <wasm file>", args[0]);
|
||||
return;
|
||||
}
|
||||
// Example executable takes one argument which must
|
||||
// refernce the existing file with a valid wasm module
|
||||
let args: Vec<_> = args().collect();
|
||||
if args.len() < 2 {
|
||||
println!("Prints export function names with and their types");
|
||||
println!("Usage: {} <wasm file>", args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Here we load module using dedicated for this purpose
|
||||
// `deserialize_file` function (which works only with modules)
|
||||
let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized");
|
||||
// Here we load module using dedicated for this purpose
|
||||
// `deserialize_file` function (which works only with modules)
|
||||
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
|
||||
// wasm module obliged to contain export section. So in case there is no
|
||||
// any export section, we panic with the corresponding error.
|
||||
let export_section = module.export_section().expect("No export section found");
|
||||
// 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
|
||||
// any export section, we panic with the corresponding error.
|
||||
let export_section = module.export_section().expect("No export section found");
|
||||
|
||||
// Process all exports, leaving only those which reference the internal function
|
||||
// of the wasm module
|
||||
let exports: Vec<String> = export_section.entries().iter()
|
||||
.filter_map(|entry|
|
||||
// This is match on export variant, which can be function, global,table or memory
|
||||
// We are interested only in functions for an example
|
||||
match *entry.internal() {
|
||||
// Return function export name (return by field() function and it's index)
|
||||
Internal::Function(index) => Some((entry.field(), index as usize)),
|
||||
_ => None
|
||||
})
|
||||
// Another map to resolve function signature index given it's internal index and return
|
||||
// the printable string of the export
|
||||
.map(|(field, index)| format!("{:}: {:?}", field, type_by_index(&module, index).params())).collect();
|
||||
// Process all exports, leaving only those which reference the internal function
|
||||
// of the wasm module
|
||||
let exports: Vec<String> = export_section.entries().iter()
|
||||
.filter_map(|entry|
|
||||
// This is match on export variant, which can be function, global,table or memory
|
||||
// We are interested only in functions for an example
|
||||
match *entry.internal() {
|
||||
// Return function export name (return by field() function and it's index)
|
||||
Internal::Function(index) => Some((entry.field(), index as usize)),
|
||||
_ => None
|
||||
})
|
||||
// Another map to resolve function signature index given it's internal index and return
|
||||
// the printable string of the export
|
||||
.map(|(field, index)| format!("{:}: {:?}", field, type_by_index(&module, index).params())).collect();
|
||||
|
||||
// Print the result
|
||||
for export in exports {
|
||||
println!("{:}", export);
|
||||
}
|
||||
// Print the result
|
||||
for export in exports {
|
||||
println!("{:}", export);
|
||||
}
|
||||
}
|
||||
|
@ -4,40 +4,40 @@ use std::env;
|
||||
use parity_wasm::elements::Section;
|
||||
|
||||
fn main() {
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 2 {
|
||||
println!("Usage: {} somefile.wasm", args[0]);
|
||||
return;
|
||||
}
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 2 {
|
||||
println!("Usage: {} somefile.wasm", args[0]);
|
||||
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() {
|
||||
match *section {
|
||||
Section::Import(ref import_section) => {
|
||||
println!(" Imports: {}", import_section.entries().len());
|
||||
import_section.entries().iter().map(|e| println!(" {}.{}", e.module(), e.field())).count();
|
||||
},
|
||||
Section::Export(ref exports_section) => {
|
||||
println!(" Exports: {}", exports_section.entries().len());
|
||||
exports_section.entries().iter().map(|e| println!(" {}", e.field())).count();
|
||||
},
|
||||
Section::Function(ref function_section) => {
|
||||
println!(" Functions: {}", function_section.entries().len());
|
||||
},
|
||||
Section::Type(ref type_section) => {
|
||||
println!(" Types: {}", type_section.types().len());
|
||||
},
|
||||
Section::Global(ref globals_section) => {
|
||||
println!(" Globals: {}", globals_section.entries().len());
|
||||
},
|
||||
Section::Data(ref data_section) if data_section.entries().len() > 0 => {
|
||||
let data = &data_section.entries()[0];
|
||||
println!(" Data size: {}", data.value().len());
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
for section in module.sections() {
|
||||
match *section {
|
||||
Section::Import(ref import_section) => {
|
||||
println!(" Imports: {}", import_section.entries().len());
|
||||
import_section.entries().iter().map(|e| println!(" {}.{}", e.module(), e.field())).count();
|
||||
},
|
||||
Section::Export(ref exports_section) => {
|
||||
println!(" Exports: {}", exports_section.entries().len());
|
||||
exports_section.entries().iter().map(|e| println!(" {}", e.field())).count();
|
||||
},
|
||||
Section::Function(ref function_section) => {
|
||||
println!(" Functions: {}", function_section.entries().len());
|
||||
},
|
||||
Section::Type(ref type_section) => {
|
||||
println!(" Types: {}", type_section.types().len());
|
||||
},
|
||||
Section::Global(ref globals_section) => {
|
||||
println!(" Globals: {}", globals_section.entries().len());
|
||||
},
|
||||
Section::Data(ref data_section) if data_section.entries().len() > 0 => {
|
||||
let data = &data_section.entries()[0];
|
||||
println!(" Data size: {}", data.value().len());
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
@ -6,58 +6,58 @@ use parity_wasm::elements;
|
||||
use parity_wasm::builder;
|
||||
|
||||
pub fn inject_nop(opcodes: &mut elements::Opcodes) {
|
||||
use parity_wasm::elements::Opcode::*;
|
||||
let opcodes = opcodes.elements_mut();
|
||||
let mut position = 0;
|
||||
loop {
|
||||
let need_inject = match &opcodes[position] {
|
||||
&Block(_) | &If(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
if need_inject {
|
||||
opcodes.insert(position + 1, Nop);
|
||||
}
|
||||
use parity_wasm::elements::Opcode::*;
|
||||
let opcodes = opcodes.elements_mut();
|
||||
let mut position = 0;
|
||||
loop {
|
||||
let need_inject = match &opcodes[position] {
|
||||
&Block(_) | &If(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
if need_inject {
|
||||
opcodes.insert(position + 1, Nop);
|
||||
}
|
||||
|
||||
position += 1;
|
||||
if position >= opcodes.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
position += 1;
|
||||
if position >= opcodes.len() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 3 {
|
||||
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
|
||||
return;
|
||||
}
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 3 {
|
||||
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
|
||||
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() {
|
||||
match section {
|
||||
&mut elements::Section::Code(ref mut code_section) => {
|
||||
for ref mut func_body in code_section.bodies_mut() {
|
||||
inject_nop(func_body.code_mut());
|
||||
}
|
||||
},
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
for section in module.sections_mut() {
|
||||
match section {
|
||||
&mut elements::Section::Code(ref mut code_section) => {
|
||||
for ref mut func_body in code_section.bodies_mut() {
|
||||
inject_nop(func_body.code_mut());
|
||||
}
|
||||
},
|
||||
_ => { }
|
||||
}
|
||||
}
|
||||
|
||||
let mut build = builder::from_module(module);
|
||||
let import_sig = build.push_signature(
|
||||
builder::signature()
|
||||
.param().i32()
|
||||
.param().i32()
|
||||
.return_type().i32()
|
||||
.build_sig()
|
||||
);
|
||||
let build = build.import()
|
||||
.module("env")
|
||||
.field("log")
|
||||
.external().func(import_sig)
|
||||
.build();
|
||||
let mut build = builder::from_module(module);
|
||||
let import_sig = build.push_signature(
|
||||
builder::signature()
|
||||
.param().i32()
|
||||
.param().i32()
|
||||
.return_type().i32()
|
||||
.build_sig()
|
||||
);
|
||||
let build = build.import()
|
||||
.module("env")
|
||||
.field("log")
|
||||
.external().func(import_sig)
|
||||
.build();
|
||||
|
||||
parity_wasm::serialize_to_file(&args[2], build.build()).unwrap();
|
||||
parity_wasm::serialize_to_file(&args[2], build.build()).unwrap();
|
||||
}
|
@ -7,30 +7,30 @@ use std::env::args;
|
||||
use parity_wasm::ModuleInstanceInterface;
|
||||
|
||||
fn main() {
|
||||
let args: Vec<_> = args().collect();
|
||||
if args.len() != 3 {
|
||||
println!("Usage: {} <wasm file> <arg>", args[0]);
|
||||
println!(" wasm file should contain exported `_call` function with single I32 argument");
|
||||
return;
|
||||
}
|
||||
let args: Vec<_> = args().collect();
|
||||
if args.len() != 3 {
|
||||
println!("Usage: {} <wasm file> <arg>", args[0]);
|
||||
println!(" wasm file should contain exported `_call` function with single I32 argument");
|
||||
return;
|
||||
}
|
||||
|
||||
// Intrepreter initialization.
|
||||
let program = parity_wasm::ProgramInstance::new();
|
||||
// Intrepreter initialization.
|
||||
let program = parity_wasm::ProgramInstance::new();
|
||||
|
||||
// Here we load module using dedicated for this purpose
|
||||
// `deserialize_file` function (which works only with modules)
|
||||
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
||||
// Here we load module using dedicated for this purpose
|
||||
// `deserialize_file` function (which works only with modules)
|
||||
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
||||
|
||||
// Intialize deserialized module. It adds module into It expects 3 parameters:
|
||||
// - a name for the module
|
||||
// - a module declaration
|
||||
// - "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
|
||||
let module = program.add_module("main", module, None).expect("Failed to initialize module");
|
||||
// Intialize deserialized module. It adds module into It expects 3 parameters:
|
||||
// - a name for the module
|
||||
// - a module declaration
|
||||
// - "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
|
||||
let module = program.add_module("main", module, None).expect("Failed to initialize module");
|
||||
|
||||
// The argument should be parsable as a valid integer
|
||||
let argument: i32 = args[2].parse().expect("Integer argument required");
|
||||
// The argument should be parsable as a valid integer
|
||||
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
|
||||
println!("Result: {:?}", module.execute_export("_call", vec![parity_wasm::RuntimeValue::I32(argument)].into()));
|
||||
// "_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()));
|
||||
}
|
||||
|
@ -5,80 +5,79 @@ use std::env::args;
|
||||
use parity_wasm::{interpreter, ModuleInstanceInterface, RuntimeValue};
|
||||
use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType};
|
||||
|
||||
|
||||
fn main() {
|
||||
let args: Vec<_> = args().collect();
|
||||
if args.len() < 3 {
|
||||
println!("Usage: {} <wasm file> <exported func> [<arg>...]", args[0]);
|
||||
return;
|
||||
}
|
||||
let func_name = &args[2];
|
||||
let (_, program_args) = args.split_at(3);
|
||||
let args: Vec<_> = args().collect();
|
||||
if args.len() < 3 {
|
||||
println!("Usage: {} <wasm file> <exported func> [<arg>...]", args[0]);
|
||||
return;
|
||||
}
|
||||
let func_name = &args[2];
|
||||
let (_, program_args) = args.split_at(3);
|
||||
|
||||
// Intrepreter initialization.
|
||||
let program = parity_wasm::ProgramInstance::new();
|
||||
// Intrepreter initialization.
|
||||
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
|
||||
let execution_params = {
|
||||
// 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");
|
||||
// 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");
|
||||
// Type section stores function types which are referenced by function_section entries
|
||||
let type_section = module.type_section().expect("No type section found");
|
||||
// Extracts call arguments from command-line arguments
|
||||
let execution_params = {
|
||||
// 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");
|
||||
// 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");
|
||||
// Type section stores function types which are referenced by function_section entries
|
||||
let type_section = module.type_section().expect("No type section found");
|
||||
|
||||
// Given function name used to find export section entry which contains
|
||||
// an `internal` field which points to the index in the function index space
|
||||
let found_entry = export_section.entries().iter()
|
||||
.find(|entry| func_name == entry.field()).expect(&format!("No export with name {} found", func_name));
|
||||
// Given function name used to find export section entry which contains
|
||||
// an `internal` field which points to the index in the function index space
|
||||
let found_entry = export_section.entries().iter()
|
||||
.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)
|
||||
let function_index: usize = match found_entry.internal() {
|
||||
&Internal::Function(index) => index as usize,
|
||||
_ => panic!("Founded export is not a function"),
|
||||
};
|
||||
// Function index in the function index space (internally-defined + imported)
|
||||
let function_index: usize = match found_entry.internal() {
|
||||
&Internal::Function(index) => index as usize,
|
||||
_ => panic!("Founded export is not a function"),
|
||||
};
|
||||
|
||||
// We need to count import section entries (functions only!) to subtract it from function_index
|
||||
// and obtain the index within the function section
|
||||
let import_section_len: usize = match module.import_section() {
|
||||
Some(import) =>
|
||||
import.entries().iter().filter(|entry| match entry.external() {
|
||||
&External::Function(_) => true,
|
||||
_ => false,
|
||||
}).count(),
|
||||
None => 0,
|
||||
};
|
||||
// We need to count import section entries (functions only!) to subtract it from function_index
|
||||
// and obtain the index within the function section
|
||||
let import_section_len: usize = match module.import_section() {
|
||||
Some(import) =>
|
||||
import.entries().iter().filter(|entry| match entry.external() {
|
||||
&External::Function(_) => true,
|
||||
_ => false,
|
||||
}).count(),
|
||||
None => 0,
|
||||
};
|
||||
|
||||
// Calculates a function index within module's function section
|
||||
let function_index_in_section = function_index - import_section_len;
|
||||
// Calculates a function index within module's function section
|
||||
let function_index_in_section = function_index - import_section_len;
|
||||
|
||||
// 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;
|
||||
// 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;
|
||||
|
||||
// Use the reference to get an actual function type
|
||||
let function_type: &FunctionType = match &type_section.types()[func_type_ref] {
|
||||
&Type::Function(ref func_type) => func_type,
|
||||
};
|
||||
// Use the reference to get an actual function type
|
||||
let function_type: &FunctionType = match &type_section.types()[func_type_ref] {
|
||||
&Type::Function(ref func_type) => func_type,
|
||||
};
|
||||
|
||||
// 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 {
|
||||
&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::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]))),
|
||||
}).collect();
|
||||
// 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 {
|
||||
&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::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]))),
|
||||
}).collect();
|
||||
|
||||
interpreter::ExecutionParams::from(args)
|
||||
};
|
||||
interpreter::ExecutionParams::from(args)
|
||||
};
|
||||
|
||||
// Intialize deserialized module. It adds module into It expects 3 parameters:
|
||||
// - a name for the module
|
||||
// - a module declaration
|
||||
// - "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
|
||||
let module = program.add_module("main", module, None).expect("Failed to initialize module");
|
||||
// Intialize deserialized module. It adds module into It expects 3 parameters:
|
||||
// - a name for the module
|
||||
// - a module declaration
|
||||
// - "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
|
||||
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(""));
|
||||
}
|
||||
|
@ -3,24 +3,24 @@ extern crate parity_wasm;
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 3 {
|
||||
println!("Usage: {} in.wasm out.wasm", args[0]);
|
||||
return;
|
||||
}
|
||||
let args = env::args().collect::<Vec<_>>();
|
||||
if args.len() != 3 {
|
||||
println!("Usage: {} in.wasm out.wasm", args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
let module = match parity_wasm::deserialize_file(&args[1])
|
||||
.expect("Failed to load module")
|
||||
.parse_names()
|
||||
{
|
||||
Ok(m) => m,
|
||||
Err((errors, m)) => {
|
||||
for (index, error) in errors.into_iter() {
|
||||
println!("Custom section #{} parse error: {:?}", index, error);
|
||||
}
|
||||
m
|
||||
}
|
||||
};
|
||||
let module = match parity_wasm::deserialize_file(&args[1])
|
||||
.expect("Failed to load module")
|
||||
.parse_names()
|
||||
{
|
||||
Ok(m) => m,
|
||||
Err((errors, m)) => {
|
||||
for (index, error) in errors.into_iter() {
|
||||
println!("Custom section #{} parse error: {:?}", index, error);
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
@ -5,15 +5,15 @@ extern crate parity_wasm;
|
||||
extern crate binaryen;
|
||||
|
||||
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.
|
||||
// assert!(binaryen_module.is_valid());
|
||||
// enable binaryen's validation if in doubt.
|
||||
// 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)
|
||||
.expect(
|
||||
"deserialize output of wasm-opt, indicating possible bug in deserializer",
|
||||
);
|
||||
let _module: parity_wasm::elements::Module = parity_wasm::deserialize_buffer(&wasm)
|
||||
.expect(
|
||||
"deserialize output of wasm-opt, indicating possible bug in deserializer",
|
||||
);
|
||||
});
|
||||
|
@ -1,16 +1,16 @@
|
||||
macro_rules! run_test {
|
||||
($label: expr, $test_name: ident, fail) => (
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
::run::failing_spec($label)
|
||||
}
|
||||
);
|
||||
($label: expr, $test_name: ident) => (
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
::run::spec($label)
|
||||
}
|
||||
);
|
||||
($label: expr, $test_name: ident, fail) => (
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
::run::failing_spec($label)
|
||||
}
|
||||
);
|
||||
($label: expr, $test_name: ident) => (
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
::run::spec($label)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
run_test!("address-offset-range.fail", wasm_address_offset_range_fail, fail);
|
||||
|
458
spec/src/run.rs
458
spec/src/run.rs
@ -10,276 +10,276 @@ use serde_json;
|
||||
use test;
|
||||
use parity_wasm::{self, elements, builder};
|
||||
use parity_wasm::interpreter::{
|
||||
RuntimeValue,
|
||||
ProgramInstance, ModuleInstance,
|
||||
ItemIndex, ExportEntryType,
|
||||
Error as InterpreterError,
|
||||
RuntimeValue,
|
||||
ProgramInstance, ModuleInstance,
|
||||
ItemIndex, ExportEntryType,
|
||||
Error as InterpreterError,
|
||||
};
|
||||
|
||||
fn spec_test_module() -> elements::Module {
|
||||
builder::module()
|
||||
.function().signature().build().body().build().build()
|
||||
.function().signature().param().i32().build().body().build().build()
|
||||
.function().signature().param().i64().build().body().build().build()
|
||||
.function().signature().param().f32().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().f64().param().f64().build().body().build().build()
|
||||
.global().value_type().i32().init_expr(elements::Opcode::I32Const(666)).build()
|
||||
.with_table(elements::TableType::new(100, None))
|
||||
.memory().with_min(1).with_max(Some(2)).build()
|
||||
.export().field("print").internal().func(0).build()
|
||||
.export().field("print").internal().func(1).build()
|
||||
.export().field("print").internal().func(2).build()
|
||||
.export().field("print").internal().func(3).build()
|
||||
.export().field("print").internal().func(4).build()
|
||||
.export().field("print").internal().func(5).build()
|
||||
.export().field("print").internal().func(6).build()
|
||||
.export().field("global").internal().global(0).build()
|
||||
.export().field("table").internal().table(0).build()
|
||||
.export().field("memory").internal().memory(0).build()
|
||||
.build()
|
||||
builder::module()
|
||||
.function().signature().build().body().build().build()
|
||||
.function().signature().param().i32().build().body().build().build()
|
||||
.function().signature().param().i64().build().body().build().build()
|
||||
.function().signature().param().f32().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().f64().param().f64().build().body().build().build()
|
||||
.global().value_type().i32().init_expr(elements::Opcode::I32Const(666)).build()
|
||||
.with_table(elements::TableType::new(100, None))
|
||||
.memory().with_min(1).with_max(Some(2)).build()
|
||||
.export().field("print").internal().func(0).build()
|
||||
.export().field("print").internal().func(1).build()
|
||||
.export().field("print").internal().func(2).build()
|
||||
.export().field("print").internal().func(3).build()
|
||||
.export().field("print").internal().func(4).build()
|
||||
.export().field("print").internal().func(5).build()
|
||||
.export().field("print").internal().func(6).build()
|
||||
.export().field("global").internal().global(0).build()
|
||||
.export().field("table").internal().table(0).build()
|
||||
.export().field("memory").internal().memory(0).build()
|
||||
.build()
|
||||
}
|
||||
|
||||
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_instance = program.add_module(module_name, module, None).expect(&format!("Failed adding {} module", module_name));
|
||||
module_instance
|
||||
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));
|
||||
module_instance
|
||||
}
|
||||
|
||||
fn try_deserialize(base_dir: &str, module_path: &str) -> Result<elements::Module, elements::Error> {
|
||||
let mut wasm_path = PathBuf::from(base_dir.clone());
|
||||
wasm_path.push(module_path);
|
||||
parity_wasm::deserialize_file(&wasm_path)
|
||||
let mut wasm_path = PathBuf::from(base_dir.clone());
|
||||
wasm_path.push(module_path);
|
||||
parity_wasm::deserialize_file(&wasm_path)
|
||||
}
|
||||
|
||||
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 program = ProgramInstance::new();
|
||||
program.add_module("try_load", module, None).map(|_| ())
|
||||
let module = try_deserialize(base_dir, module_path).map_err(|e| parity_wasm::interpreter::Error::Program(format!("{:?}", e)))?;
|
||||
let program = ProgramInstance::new();
|
||||
program.add_module("try_load", module, None).map(|_| ())
|
||||
}
|
||||
|
||||
fn runtime_value(test_val: &test::RuntimeValue) -> parity_wasm::RuntimeValue {
|
||||
match test_val.value_type.as_ref() {
|
||||
"i32" => {
|
||||
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
||||
parity_wasm::RuntimeValue::I32(unsigned as i32)
|
||||
},
|
||||
"i64" => {
|
||||
let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
|
||||
parity_wasm::RuntimeValue::I64(unsigned as i64)
|
||||
},
|
||||
"f32" => {
|
||||
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
||||
parity_wasm::RuntimeValue::decode_f32(unsigned)
|
||||
},
|
||||
"f64" => {
|
||||
let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
|
||||
parity_wasm::RuntimeValue::decode_f64(unsigned)
|
||||
},
|
||||
_ => panic!("Unknwon runtime value type"),
|
||||
}
|
||||
match test_val.value_type.as_ref() {
|
||||
"i32" => {
|
||||
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
||||
parity_wasm::RuntimeValue::I32(unsigned as i32)
|
||||
},
|
||||
"i64" => {
|
||||
let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
|
||||
parity_wasm::RuntimeValue::I64(unsigned as i64)
|
||||
},
|
||||
"f32" => {
|
||||
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
||||
parity_wasm::RuntimeValue::decode_f32(unsigned)
|
||||
},
|
||||
"f64" => {
|
||||
let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
|
||||
parity_wasm::RuntimeValue::decode_f64(unsigned)
|
||||
},
|
||||
_ => panic!("Unknwon runtime value type"),
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
-> Result<Option<parity_wasm::RuntimeValue>, InterpreterError>
|
||||
-> Result<Option<parity_wasm::RuntimeValue>, InterpreterError>
|
||||
{
|
||||
match *action {
|
||||
test::Action::Invoke { ref module, ref field, ref args } => {
|
||||
let module = module.clone().unwrap_or("wasm_test".into());
|
||||
let module = module.trim_left_matches('$');
|
||||
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())
|
||||
},
|
||||
test::Action::Get { ref module, ref field, .. } => {
|
||||
let module = module.clone().unwrap_or("wasm_test".into());
|
||||
let module = module.trim_left_matches('$');
|
||||
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
|
||||
let field = jstring_to_rstring(&field);
|
||||
match *action {
|
||||
test::Action::Invoke { ref module, ref field, ref args } => {
|
||||
let module = module.clone().unwrap_or("wasm_test".into());
|
||||
let module = module.trim_left_matches('$');
|
||||
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())
|
||||
},
|
||||
test::Action::Get { ref module, ref field, .. } => {
|
||||
let module = module.clone().unwrap_or("wasm_test".into());
|
||||
let module = module.trim_left_matches('$');
|
||||
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
|
||||
let field = jstring_to_rstring(&field);
|
||||
|
||||
module.export_entry(field.as_ref(), &ExportEntryType::Any)
|
||||
.and_then(|i| match i {
|
||||
elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)),
|
||||
_ => 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())))
|
||||
}
|
||||
}
|
||||
module.export_entry(field.as_ref(), &ExportEntryType::Any)
|
||||
.and_then(|i| match i {
|
||||
elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)),
|
||||
_ => 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())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FixtureParams {
|
||||
failing: bool,
|
||||
json: String,
|
||||
failing: bool,
|
||||
json: String,
|
||||
}
|
||||
|
||||
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());
|
||||
wast2wasm_path.push("bin");
|
||||
wast2wasm_path.push("wast2wasm");
|
||||
let mut wast2wasm_path = PathBuf::from(outdir.clone());
|
||||
wast2wasm_path.push("bin");
|
||||
wast2wasm_path.push("wast2wasm");
|
||||
|
||||
let mut json_spec_path = PathBuf::from(outdir.clone());
|
||||
json_spec_path.push(&format!("{}.json", name));
|
||||
let mut json_spec_path = PathBuf::from(outdir.clone());
|
||||
json_spec_path.push(&format!("{}.json", name));
|
||||
|
||||
let wast2wasm_output = Command::new(wast2wasm_path)
|
||||
.arg("--spec")
|
||||
.arg("-o")
|
||||
.arg(&json_spec_path)
|
||||
.arg(&format!("./wabt/third_party/testsuite/{}.wast", name))
|
||||
.output()
|
||||
.expect("Failed to execute process");
|
||||
let wast2wasm_output = Command::new(wast2wasm_path)
|
||||
.arg("--spec")
|
||||
.arg("-o")
|
||||
.arg(&json_spec_path)
|
||||
.arg(&format!("./wabt/third_party/testsuite/{}.wast", name))
|
||||
.output()
|
||||
.expect("Failed to execute process");
|
||||
|
||||
FixtureParams {
|
||||
json: json_spec_path.to_str().unwrap().to_owned(),
|
||||
failing: {
|
||||
if !wast2wasm_output.status.success() {
|
||||
println!("wasm2wast error code: {}", wast2wasm_output.status);
|
||||
println!("wasm2wast stdout: {}", String::from_utf8_lossy(&wast2wasm_output.stdout));
|
||||
println!("wasm2wast stderr: {}", String::from_utf8_lossy(&wast2wasm_output.stderr));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
FixtureParams {
|
||||
json: json_spec_path.to_str().unwrap().to_owned(),
|
||||
failing: {
|
||||
if !wast2wasm_output.status.success() {
|
||||
println!("wasm2wast error code: {}", wast2wasm_output.status);
|
||||
println!("wasm2wast stdout: {}", String::from_utf8_lossy(&wast2wasm_output.stdout));
|
||||
println!("wasm2wast stderr: {}", String::from_utf8_lossy(&wast2wasm_output.stderr));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn failing_spec(name: &str) {
|
||||
let fixture = run_wast2wasm(name);
|
||||
if !fixture.failing {
|
||||
panic!("wasm2wast expected to fail, but terminated normally");
|
||||
}
|
||||
let fixture = run_wast2wasm(name);
|
||||
if !fixture.failing {
|
||||
panic!("wasm2wast expected to fail, but terminated normally");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spec(name: &str) {
|
||||
let outdir = env::var("OUT_DIR").unwrap();
|
||||
let outdir = env::var("OUT_DIR").unwrap();
|
||||
|
||||
let fixture = run_wast2wasm(name);
|
||||
if fixture.failing {
|
||||
panic!("wasm2wast terminated abnormally, expected to success");
|
||||
}
|
||||
let fixture = run_wast2wasm(name);
|
||||
if fixture.failing {
|
||||
panic!("wasm2wast terminated abnormally, expected to success");
|
||||
}
|
||||
|
||||
let mut f = File::open(&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 mut f = File::open(&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 program = ProgramInstance::new();
|
||||
let mut last_module = None;
|
||||
for command in &spec.commands {
|
||||
println!("command {:?}", command);
|
||||
match command {
|
||||
&test::Command::Module { ref name, ref filename, .. } => {
|
||||
last_module = Some(load_module(&outdir, &filename, &name, &program));
|
||||
},
|
||||
&test::Command::AssertReturn { line, ref action, ref expected } => {
|
||||
let result = run_action(&program, action);
|
||||
match result {
|
||||
Ok(result) => {
|
||||
let spec_expected = runtime_values(expected);
|
||||
let actual_result = result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>();
|
||||
for (actual_result, spec_expected) in actual_result.iter().zip(spec_expected.iter()) {
|
||||
assert_eq!(actual_result.variable_type(), spec_expected.variable_type());
|
||||
// f32::NAN != f32::NAN
|
||||
match spec_expected {
|
||||
&RuntimeValue::F32(val) if val.is_nan() => match actual_result {
|
||||
&RuntimeValue::F32(val) => assert!(val.is_nan()),
|
||||
_ => unreachable!(), // checked above that types are same
|
||||
},
|
||||
&RuntimeValue::F64(val) if val.is_nan() => match actual_result {
|
||||
&RuntimeValue::F64(val) => assert!(val.is_nan()),
|
||||
_ => unreachable!(), // checked above that types are same
|
||||
},
|
||||
spec_expected @ _ => assert_eq!(actual_result, spec_expected),
|
||||
}
|
||||
}
|
||||
println!("assert_return at line {} - success", line);
|
||||
},
|
||||
Err(e) => {
|
||||
panic!("Expected action to return value, got error: {:?}", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
&test::Command::AssertReturnCanonicalNan { line, ref action } | &test::Command::AssertReturnArithmeticNan { line, ref action } => {
|
||||
let result = run_action(&program, action);
|
||||
match result {
|
||||
Ok(result) => {
|
||||
for actual_result in result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>() {
|
||||
match actual_result {
|
||||
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) },
|
||||
val @ _ => panic!("Expected action to return float value, got {:?}", val),
|
||||
}
|
||||
}
|
||||
println!("assert_return_nan at line {} - success", line);
|
||||
},
|
||||
Err(e) => {
|
||||
panic!("Expected action to return value, got error: {:?}", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
&test::Command::AssertExhaustion { line, ref action, .. } => {
|
||||
let result = run_action(&program, action);
|
||||
match result {
|
||||
Ok(result) => panic!("Expected exhaustion, got result: {:?}", result),
|
||||
Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e),
|
||||
}
|
||||
},
|
||||
&test::Command::AssertTrap { line, ref action, .. } => {
|
||||
let result = run_action(&program, action);
|
||||
match result {
|
||||
Ok(result) => {
|
||||
panic!("Expected action to result in a trap, got result: {:?}", result);
|
||||
},
|
||||
Err(e) => {
|
||||
println!("assert_trap at line {} - success ({:?})", line, e);
|
||||
}
|
||||
}
|
||||
},
|
||||
&test::Command::AssertInvalid { line, ref filename, .. }
|
||||
| &test::Command::AssertMalformed { line, ref filename, .. }
|
||||
| &test::Command::AssertUnlinkable { line, ref filename, .. }
|
||||
=> {
|
||||
let module_load = try_load(&outdir, filename);
|
||||
match module_load {
|
||||
Ok(_) => {
|
||||
panic!("Expected invalid module definition, got some module!")
|
||||
},
|
||||
Err(e) => {
|
||||
println!("assert_invalid at line {} - success ({:?})", line, e)
|
||||
}
|
||||
}
|
||||
},
|
||||
&test::Command::AssertUninstantiable { line, ref filename, .. } => {
|
||||
match try_load(&outdir, &filename) {
|
||||
Ok(_) => panic!("Expected error running start function at line {}", line),
|
||||
Err(e) => println!("assert_uninstantiable - success ({:?})", e),
|
||||
}
|
||||
},
|
||||
&test::Command::Register { ref name, ref as_name, .. } => {
|
||||
match name {
|
||||
&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(),
|
||||
}
|
||||
},
|
||||
&test::Command::Action { line, ref action } => {
|
||||
match run_action(&program, action) {
|
||||
Ok(_) => { },
|
||||
Err(e) => {
|
||||
panic!("Failed to invoke action at line {}: {:?}", line, e)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
let program = ProgramInstance::new();
|
||||
let mut last_module = None;
|
||||
for command in &spec.commands {
|
||||
println!("command {:?}", command);
|
||||
match command {
|
||||
&test::Command::Module { ref name, ref filename, .. } => {
|
||||
last_module = Some(load_module(&outdir, &filename, &name, &program));
|
||||
},
|
||||
&test::Command::AssertReturn { line, ref action, ref expected } => {
|
||||
let result = run_action(&program, action);
|
||||
match result {
|
||||
Ok(result) => {
|
||||
let spec_expected = runtime_values(expected);
|
||||
let actual_result = result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>();
|
||||
for (actual_result, spec_expected) in actual_result.iter().zip(spec_expected.iter()) {
|
||||
assert_eq!(actual_result.variable_type(), spec_expected.variable_type());
|
||||
// f32::NAN != f32::NAN
|
||||
match spec_expected {
|
||||
&RuntimeValue::F32(val) if val.is_nan() => match actual_result {
|
||||
&RuntimeValue::F32(val) => assert!(val.is_nan()),
|
||||
_ => unreachable!(), // checked above that types are same
|
||||
},
|
||||
&RuntimeValue::F64(val) if val.is_nan() => match actual_result {
|
||||
&RuntimeValue::F64(val) => assert!(val.is_nan()),
|
||||
_ => unreachable!(), // checked above that types are same
|
||||
},
|
||||
spec_expected @ _ => assert_eq!(actual_result, spec_expected),
|
||||
}
|
||||
}
|
||||
println!("assert_return at line {} - success", line);
|
||||
},
|
||||
Err(e) => {
|
||||
panic!("Expected action to return value, got error: {:?}", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
&test::Command::AssertReturnCanonicalNan { line, ref action } | &test::Command::AssertReturnArithmeticNan { line, ref action } => {
|
||||
let result = run_action(&program, action);
|
||||
match result {
|
||||
Ok(result) => {
|
||||
for actual_result in result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>() {
|
||||
match actual_result {
|
||||
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) },
|
||||
val @ _ => panic!("Expected action to return float value, got {:?}", val),
|
||||
}
|
||||
}
|
||||
println!("assert_return_nan at line {} - success", line);
|
||||
},
|
||||
Err(e) => {
|
||||
panic!("Expected action to return value, got error: {:?}", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
&test::Command::AssertExhaustion { line, ref action, .. } => {
|
||||
let result = run_action(&program, action);
|
||||
match result {
|
||||
Ok(result) => panic!("Expected exhaustion, got result: {:?}", result),
|
||||
Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e),
|
||||
}
|
||||
},
|
||||
&test::Command::AssertTrap { line, ref action, .. } => {
|
||||
let result = run_action(&program, action);
|
||||
match result {
|
||||
Ok(result) => {
|
||||
panic!("Expected action to result in a trap, got result: {:?}", result);
|
||||
},
|
||||
Err(e) => {
|
||||
println!("assert_trap at line {} - success ({:?})", line, e);
|
||||
}
|
||||
}
|
||||
},
|
||||
&test::Command::AssertInvalid { line, ref filename, .. }
|
||||
| &test::Command::AssertMalformed { line, ref filename, .. }
|
||||
| &test::Command::AssertUnlinkable { line, ref filename, .. }
|
||||
=> {
|
||||
let module_load = try_load(&outdir, filename);
|
||||
match module_load {
|
||||
Ok(_) => {
|
||||
panic!("Expected invalid module definition, got some module!")
|
||||
},
|
||||
Err(e) => {
|
||||
println!("assert_invalid at line {} - success ({:?})", line, e)
|
||||
}
|
||||
}
|
||||
},
|
||||
&test::Command::AssertUninstantiable { line, ref filename, .. } => {
|
||||
match try_load(&outdir, &filename) {
|
||||
Ok(_) => panic!("Expected error running start function at line {}", line),
|
||||
Err(e) => println!("assert_uninstantiable - success ({:?})", e),
|
||||
}
|
||||
},
|
||||
&test::Command::Register { ref name, ref as_name, .. } => {
|
||||
match name {
|
||||
&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(),
|
||||
}
|
||||
},
|
||||
&test::Command::Action { line, ref action } => {
|
||||
match run_action(&program, action) {
|
||||
Ok(_) => { },
|
||||
Err(e) => {
|
||||
panic!("Failed to invoke action at line {}: {:?}", line, e)
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
// This conversion is incorrect in general case (casting char to u8)!!!
|
||||
fn jstring_to_rstring(jstring: &str) -> String {
|
||||
let jstring_chars: Vec<u8> = jstring.chars().map(|c| c as u8).collect();
|
||||
let rstring = String::from_utf8(jstring_chars).unwrap();
|
||||
rstring
|
||||
let jstring_chars: Vec<u8> = jstring.chars().map(|c| c as u8).collect();
|
||||
let rstring = String::from_utf8(jstring_chars).unwrap();
|
||||
rstring
|
||||
}
|
||||
|
170
spec/src/test.rs
170
spec/src/test.rs
@ -2,103 +2,103 @@
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct RuntimeValue {
|
||||
#[serde(rename = "type")]
|
||||
pub value_type: String,
|
||||
pub value: String,
|
||||
#[serde(rename = "type")]
|
||||
pub value_type: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Action {
|
||||
#[serde(rename = "invoke")]
|
||||
Invoke {
|
||||
module: Option<String>,
|
||||
field: String,
|
||||
args: Vec<RuntimeValue>,
|
||||
},
|
||||
#[serde(rename = "get")]
|
||||
Get {
|
||||
module: Option<String>,
|
||||
field: String,
|
||||
}
|
||||
#[serde(rename = "invoke")]
|
||||
Invoke {
|
||||
module: Option<String>,
|
||||
field: String,
|
||||
args: Vec<RuntimeValue>,
|
||||
},
|
||||
#[serde(rename = "get")]
|
||||
Get {
|
||||
module: Option<String>,
|
||||
field: String,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Command {
|
||||
#[serde(rename = "module")]
|
||||
Module {
|
||||
line: u64,
|
||||
name: Option<String>,
|
||||
filename: String
|
||||
},
|
||||
#[serde(rename = "assert_return")]
|
||||
AssertReturn {
|
||||
line: u64,
|
||||
action: Action,
|
||||
expected: Vec<RuntimeValue>,
|
||||
},
|
||||
#[serde(rename = "assert_return_canonical_nan")]
|
||||
AssertReturnCanonicalNan {
|
||||
line: u64,
|
||||
action: Action,
|
||||
},
|
||||
#[serde(rename = "assert_return_arithmetic_nan")]
|
||||
AssertReturnArithmeticNan {
|
||||
line: u64,
|
||||
action: Action,
|
||||
},
|
||||
#[serde(rename = "assert_trap")]
|
||||
AssertTrap {
|
||||
line: u64,
|
||||
action: Action,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename = "assert_invalid")]
|
||||
AssertInvalid {
|
||||
line: u64,
|
||||
filename: String,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename = "assert_malformed")]
|
||||
AssertMalformed {
|
||||
line: u64,
|
||||
filename: String,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename = "assert_uninstantiable")]
|
||||
AssertUninstantiable {
|
||||
line: u64,
|
||||
filename: String,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename = "assert_exhaustion")]
|
||||
AssertExhaustion {
|
||||
line: u64,
|
||||
action: Action,
|
||||
},
|
||||
#[serde(rename = "assert_unlinkable")]
|
||||
AssertUnlinkable {
|
||||
line: u64,
|
||||
filename: String,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename = "register")]
|
||||
Register {
|
||||
line: u64,
|
||||
name: Option<String>,
|
||||
#[serde(rename = "as")]
|
||||
as_name: String,
|
||||
},
|
||||
#[serde(rename = "action")]
|
||||
Action {
|
||||
line: u64,
|
||||
action: Action,
|
||||
},
|
||||
#[serde(rename = "module")]
|
||||
Module {
|
||||
line: u64,
|
||||
name: Option<String>,
|
||||
filename: String
|
||||
},
|
||||
#[serde(rename = "assert_return")]
|
||||
AssertReturn {
|
||||
line: u64,
|
||||
action: Action,
|
||||
expected: Vec<RuntimeValue>,
|
||||
},
|
||||
#[serde(rename = "assert_return_canonical_nan")]
|
||||
AssertReturnCanonicalNan {
|
||||
line: u64,
|
||||
action: Action,
|
||||
},
|
||||
#[serde(rename = "assert_return_arithmetic_nan")]
|
||||
AssertReturnArithmeticNan {
|
||||
line: u64,
|
||||
action: Action,
|
||||
},
|
||||
#[serde(rename = "assert_trap")]
|
||||
AssertTrap {
|
||||
line: u64,
|
||||
action: Action,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename = "assert_invalid")]
|
||||
AssertInvalid {
|
||||
line: u64,
|
||||
filename: String,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename = "assert_malformed")]
|
||||
AssertMalformed {
|
||||
line: u64,
|
||||
filename: String,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename = "assert_uninstantiable")]
|
||||
AssertUninstantiable {
|
||||
line: u64,
|
||||
filename: String,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename = "assert_exhaustion")]
|
||||
AssertExhaustion {
|
||||
line: u64,
|
||||
action: Action,
|
||||
},
|
||||
#[serde(rename = "assert_unlinkable")]
|
||||
AssertUnlinkable {
|
||||
line: u64,
|
||||
filename: String,
|
||||
text: String,
|
||||
},
|
||||
#[serde(rename = "register")]
|
||||
Register {
|
||||
line: u64,
|
||||
name: Option<String>,
|
||||
#[serde(rename = "as")]
|
||||
as_name: String,
|
||||
},
|
||||
#[serde(rename = "action")]
|
||||
Action {
|
||||
line: u64,
|
||||
action: Action,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Spec {
|
||||
pub source_filename: String,
|
||||
pub commands: Vec<Command>,
|
||||
pub source_filename: String,
|
||||
pub commands: Vec<Command>,
|
||||
}
|
@ -4,170 +4,170 @@ use super::misc::{ValueTypeBuilder, ValueTypesBuilder, OptionalValueTypeBuilder}
|
||||
|
||||
/// Signature template description
|
||||
pub enum Signature {
|
||||
TypeReference(u32),
|
||||
Inline(elements::FunctionType),
|
||||
TypeReference(u32),
|
||||
Inline(elements::FunctionType),
|
||||
}
|
||||
|
||||
/// Signature builder
|
||||
pub struct SignatureBuilder<F=Identity> {
|
||||
callback: F,
|
||||
signature: elements::FunctionType,
|
||||
callback: F,
|
||||
signature: elements::FunctionType,
|
||||
}
|
||||
|
||||
impl SignatureBuilder {
|
||||
/// New signature builder
|
||||
pub fn new() -> Self {
|
||||
SignatureBuilder::with_callback(Identity)
|
||||
}
|
||||
/// New signature builder
|
||||
pub fn new() -> Self {
|
||||
SignatureBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> SignatureBuilder<F> where F: Invoke<elements::FunctionType> {
|
||||
/// New builder with callback function specified
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
SignatureBuilder {
|
||||
callback: callback,
|
||||
signature: elements::FunctionType::default(),
|
||||
}
|
||||
}
|
||||
/// New builder with callback function specified
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
SignatureBuilder {
|
||||
callback: callback,
|
||||
signature: elements::FunctionType::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add argument to signature builder
|
||||
pub fn with_param(mut self, value_type: elements::ValueType) -> Self {
|
||||
self.signature.params_mut().push(value_type);
|
||||
self
|
||||
}
|
||||
/// Add argument to signature builder
|
||||
pub fn with_param(mut self, value_type: elements::ValueType) -> Self {
|
||||
self.signature.params_mut().push(value_type);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add multiple arguments to signature builder
|
||||
pub fn with_params(mut self, value_types: Vec<elements::ValueType>) -> Self {
|
||||
self.signature.params_mut().extend(value_types);
|
||||
self
|
||||
}
|
||||
/// Add multiple arguments to signature builder
|
||||
pub fn with_params(mut self, value_types: Vec<elements::ValueType>) -> Self {
|
||||
self.signature.params_mut().extend(value_types);
|
||||
self
|
||||
}
|
||||
|
||||
/// Override signature return type
|
||||
pub fn with_return_type(mut self, return_type: Option<elements::ValueType>) -> Self {
|
||||
*self.signature.return_type_mut() = return_type;
|
||||
self
|
||||
}
|
||||
/// Override signature return type
|
||||
pub fn with_return_type(mut self, return_type: Option<elements::ValueType>) -> Self {
|
||||
*self.signature.return_type_mut() = return_type;
|
||||
self
|
||||
}
|
||||
|
||||
/// Start build new argument
|
||||
pub fn param(self) -> ValueTypeBuilder<Self> {
|
||||
ValueTypeBuilder::with_callback(self)
|
||||
}
|
||||
/// Start build new argument
|
||||
pub fn param(self) -> ValueTypeBuilder<Self> {
|
||||
ValueTypeBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Start build multiple arguments
|
||||
pub fn params(self) -> ValueTypesBuilder<Self> {
|
||||
ValueTypesBuilder::with_callback(self)
|
||||
}
|
||||
/// Start build multiple arguments
|
||||
pub fn params(self) -> ValueTypesBuilder<Self> {
|
||||
ValueTypesBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Start building return type
|
||||
pub fn return_type(self) -> OptionalValueTypeBuilder<Self> {
|
||||
OptionalValueTypeBuilder::with_callback(self)
|
||||
}
|
||||
/// Start building return type
|
||||
pub fn return_type(self) -> OptionalValueTypeBuilder<Self> {
|
||||
OptionalValueTypeBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Finish current builder
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.signature)
|
||||
}
|
||||
/// Finish current builder
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.signature)
|
||||
}
|
||||
|
||||
/// Finish current builder returning intermediate `Signature` struct
|
||||
pub fn build_sig(self) -> Signature {
|
||||
Signature::Inline(self.signature)
|
||||
}
|
||||
/// Finish current builder returning intermediate `Signature` struct
|
||||
pub fn build_sig(self) -> Signature {
|
||||
Signature::Inline(self.signature)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_params(args)
|
||||
}
|
||||
fn invoke(self, args: Vec<elements::ValueType>) -> Self {
|
||||
self.with_params(args)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_return_type(arg)
|
||||
}
|
||||
fn invoke(self, arg: Option<elements::ValueType>) -> Self {
|
||||
self.with_return_type(arg)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_param(arg)
|
||||
}
|
||||
fn invoke(self, arg: elements::ValueType) -> Self {
|
||||
self.with_param(arg)
|
||||
}
|
||||
}
|
||||
|
||||
/// Type (signature) reference builder (for function/import/indirect call)
|
||||
pub struct TypeRefBuilder<F=Identity> {
|
||||
callback: F,
|
||||
type_ref: u32,
|
||||
callback: F,
|
||||
type_ref: u32,
|
||||
}
|
||||
|
||||
impl<F> TypeRefBuilder<F> where F: Invoke<u32> {
|
||||
/// New builder chained with specified callback
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
TypeRefBuilder {
|
||||
callback: callback,
|
||||
type_ref: 0
|
||||
}
|
||||
}
|
||||
/// New builder chained with specified callback
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
TypeRefBuilder {
|
||||
callback: callback,
|
||||
type_ref: 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Set/override of type reference
|
||||
pub fn val(mut self, val: u32) -> Self {
|
||||
self.type_ref = val;
|
||||
self
|
||||
}
|
||||
/// Set/override of type reference
|
||||
pub fn val(mut self, val: u32) -> Self {
|
||||
self.type_ref = val;
|
||||
self
|
||||
}
|
||||
|
||||
/// Finish current builder
|
||||
pub fn build(self) -> F::Result { self.callback.invoke(self.type_ref) }
|
||||
/// Finish current builder
|
||||
pub fn build(self) -> F::Result { self.callback.invoke(self.type_ref) }
|
||||
}
|
||||
|
||||
/// Multiple signatures builder
|
||||
pub struct SignaturesBuilder<F=Identity> {
|
||||
callback: F,
|
||||
section: Vec<Signature>,
|
||||
callback: F,
|
||||
section: Vec<Signature>,
|
||||
}
|
||||
|
||||
impl SignaturesBuilder {
|
||||
/// New empty functions section builder
|
||||
pub fn new() -> Self {
|
||||
SignaturesBuilder::with_callback(Identity)
|
||||
}
|
||||
/// New empty functions section builder
|
||||
pub fn new() -> Self {
|
||||
SignaturesBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> SignaturesBuilder<F> {
|
||||
/// New builder chained with specified callback
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
SignaturesBuilder {
|
||||
callback: callback,
|
||||
section: Vec::new(),
|
||||
}
|
||||
}
|
||||
/// New builder chained with specified callback
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
SignaturesBuilder {
|
||||
callback: callback,
|
||||
section: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Push new signature into the builder output
|
||||
pub fn with_signature(mut self, signature: Signature) -> Self {
|
||||
self.section.push(signature);
|
||||
self
|
||||
}
|
||||
/// Push new signature into the builder output
|
||||
pub fn with_signature(mut self, signature: Signature) -> Self {
|
||||
self.section.push(signature);
|
||||
self
|
||||
}
|
||||
|
||||
/// Start building new signature with `TypeRefBuilder`
|
||||
pub fn type_ref(self) -> TypeRefBuilder<Self> {
|
||||
TypeRefBuilder::with_callback(self)
|
||||
}
|
||||
/// Start building new signature with `TypeRefBuilder`
|
||||
pub fn type_ref(self) -> TypeRefBuilder<Self> {
|
||||
TypeRefBuilder::with_callback(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> {
|
||||
/// Start building new signature with dedicated builder
|
||||
pub fn signature(self) -> SignatureBuilder<Self> {
|
||||
SignatureBuilder::with_callback(self)
|
||||
}
|
||||
/// Start building new signature with dedicated builder
|
||||
pub fn signature(self) -> SignatureBuilder<Self> {
|
||||
SignatureBuilder::with_callback(self)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_signature(Signature::Inline(signature))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_signature(Signature::TypeReference(type_ref))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> SignaturesBuilder<F> where F: Invoke<elements::FunctionSection> {
|
||||
|
||||
/// Finalize builder spawning element
|
||||
pub fn build(self) -> F::Result {
|
||||
let mut result = elements::FunctionSection::default();
|
||||
for f in self.section.into_iter() {
|
||||
if let Signature::TypeReference(type_ref) = f {
|
||||
result.entries_mut().push(elements::Func::new(type_ref));
|
||||
} else {
|
||||
unreachable!(); // never possible with current generics impl-s
|
||||
}
|
||||
}
|
||||
self.callback.invoke(result)
|
||||
}
|
||||
/// Finalize builder spawning element
|
||||
pub fn build(self) -> F::Result {
|
||||
let mut result = elements::FunctionSection::default();
|
||||
for f in self.section.into_iter() {
|
||||
if let Signature::TypeReference(type_ref) = f {
|
||||
result.entries_mut().push(elements::Func::new(type_ref));
|
||||
} else {
|
||||
unreachable!(); // never possible with current generics impl-s
|
||||
}
|
||||
}
|
||||
self.callback.invoke(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Signature bindings
|
||||
pub type SignatureBindings = Vec<Signature>;
|
||||
|
||||
impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> {
|
||||
/// Bind signature list
|
||||
pub fn bind(self) -> F::Result {
|
||||
self.callback.invoke(self.section)
|
||||
}
|
||||
/// Bind signature list
|
||||
pub fn bind(self) -> F::Result {
|
||||
self.callback.invoke(self.section)
|
||||
}
|
||||
}
|
||||
|
||||
/// Function body (code) builder
|
||||
pub struct FuncBodyBuilder<F=Identity> {
|
||||
callback: F,
|
||||
body: elements::FuncBody,
|
||||
callback: F,
|
||||
body: elements::FuncBody,
|
||||
}
|
||||
|
||||
impl<F> FuncBodyBuilder<F> {
|
||||
/// New body (code) builder given the chain callback
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
FuncBodyBuilder {
|
||||
callback: callback,
|
||||
body: elements::FuncBody::new(Vec::new(), elements::Opcodes::empty()),
|
||||
}
|
||||
}
|
||||
/// New body (code) builder given the chain callback
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
FuncBodyBuilder {
|
||||
callback: callback,
|
||||
body: elements::FuncBody::new(Vec::new(), elements::Opcodes::empty()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> FuncBodyBuilder<F> where F: Invoke<elements::FuncBody> {
|
||||
/// Set/override entirely with FuncBody struct
|
||||
pub fn with_func(mut self, func: elements::FuncBody) -> Self {
|
||||
self.body = func;
|
||||
self
|
||||
}
|
||||
/// Set/override entirely with FuncBody struct
|
||||
pub fn with_func(mut self, func: elements::FuncBody) -> Self {
|
||||
self.body = func;
|
||||
self
|
||||
}
|
||||
|
||||
/// Extend function local list with new entries
|
||||
pub fn with_locals(mut self, locals: Vec<elements::Local>) -> Self {
|
||||
self.body.locals_mut().extend(locals);
|
||||
self
|
||||
}
|
||||
/// Extend function local list with new entries
|
||||
pub fn with_locals(mut self, locals: Vec<elements::Local>) -> Self {
|
||||
self.body.locals_mut().extend(locals);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set code of the function
|
||||
pub fn with_opcodes(mut self, opcodes: elements::Opcodes) -> Self {
|
||||
*self.body.code_mut() = opcodes;
|
||||
self
|
||||
}
|
||||
/// Set code of the function
|
||||
pub fn with_opcodes(mut self, opcodes: elements::Opcodes) -> Self {
|
||||
*self.body.code_mut() = opcodes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Finish current builder spawning resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.body)
|
||||
}
|
||||
/// Finish current builder spawning resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.body)
|
||||
}
|
||||
}
|
||||
|
||||
/// Function definition (extended structure to specify function entirely, incl. signature, mainness and code)
|
||||
pub struct FunctionDefinition {
|
||||
/// Is this function is start function
|
||||
pub is_main: bool,
|
||||
/// Signature description
|
||||
pub signature: Signature,
|
||||
/// Body (code) of the function
|
||||
pub code: elements::FuncBody,
|
||||
/// Is this function is start function
|
||||
pub is_main: bool,
|
||||
/// Signature description
|
||||
pub signature: Signature,
|
||||
/// Body (code) of the function
|
||||
pub code: elements::FuncBody,
|
||||
}
|
||||
|
||||
impl Default for FunctionDefinition {
|
||||
fn default() -> Self {
|
||||
FunctionDefinition {
|
||||
is_main: false,
|
||||
signature: Signature::TypeReference(0),
|
||||
code: elements::FuncBody::empty(),
|
||||
}
|
||||
}
|
||||
fn default() -> Self {
|
||||
FunctionDefinition {
|
||||
is_main: false,
|
||||
signature: Signature::TypeReference(0),
|
||||
code: elements::FuncBody::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Function definition builder
|
||||
pub struct FunctionBuilder<F=Identity> {
|
||||
callback: F,
|
||||
func: FunctionDefinition,
|
||||
callback: F,
|
||||
func: FunctionDefinition,
|
||||
}
|
||||
|
||||
impl FunctionBuilder {
|
||||
/// New function builder
|
||||
pub fn new() -> Self {
|
||||
FunctionBuilder::with_callback(Identity)
|
||||
}
|
||||
/// New function builder
|
||||
pub fn new() -> Self {
|
||||
FunctionBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
||||
/// New function builder with chained callback
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
FunctionBuilder {
|
||||
callback: callback,
|
||||
func: Default::default(),
|
||||
}
|
||||
}
|
||||
/// New function builder with chained callback
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
FunctionBuilder {
|
||||
callback: callback,
|
||||
func: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set that this function is main entry point
|
||||
pub fn main(mut self) -> Self {
|
||||
self.func.is_main = true;
|
||||
self
|
||||
}
|
||||
/// Set that this function is main entry point
|
||||
pub fn main(mut self) -> Self {
|
||||
self.func.is_main = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Start signature builder of the function
|
||||
pub fn signature(self) -> SignatureBuilder<Self> {
|
||||
SignatureBuilder::with_callback(self)
|
||||
}
|
||||
/// Start signature builder of the function
|
||||
pub fn signature(self) -> SignatureBuilder<Self> {
|
||||
SignatureBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Override current signature entirely with new one from known struct
|
||||
pub fn with_signature(mut self, signature: Signature) -> Self {
|
||||
self.func.signature = signature;
|
||||
self
|
||||
}
|
||||
/// Override current signature entirely with new one from known struct
|
||||
pub fn with_signature(mut self, signature: Signature) -> Self {
|
||||
self.func.signature = signature;
|
||||
self
|
||||
}
|
||||
|
||||
/// Start code (body) builder
|
||||
pub fn body(self) -> FuncBodyBuilder<Self> {
|
||||
FuncBodyBuilder::with_callback(self)
|
||||
}
|
||||
/// Start code (body) builder
|
||||
pub fn body(self) -> FuncBodyBuilder<Self> {
|
||||
FuncBodyBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Set body (code) for this function
|
||||
pub fn with_body(mut self, body: elements::FuncBody) -> Self {
|
||||
self.func.code = body;
|
||||
self
|
||||
}
|
||||
/// Set body (code) for this function
|
||||
pub fn with_body(mut self, body: elements::FuncBody) -> Self {
|
||||
self.func.code = body;
|
||||
self
|
||||
}
|
||||
|
||||
/// Finalize current builder spawning resulting struct in the callback
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.func)
|
||||
}
|
||||
/// Finalize current builder spawning resulting struct in the callback
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.func)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_signature(Signature::Inline(signature))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_signature(Signature::TypeReference(type_ref))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_body(body)
|
||||
}
|
||||
fn invoke(self, body: elements::FuncBody) -> Self::Result {
|
||||
self.with_body(body)
|
||||
}
|
||||
}
|
||||
|
||||
/// New builder of signature list
|
||||
pub fn signatures() -> SignaturesBuilder {
|
||||
SignaturesBuilder::new()
|
||||
SignaturesBuilder::new()
|
||||
}
|
||||
|
||||
/// New signature builder
|
||||
pub fn signature() -> SignatureBuilder {
|
||||
SignatureBuilder::new()
|
||||
SignatureBuilder::new()
|
||||
}
|
||||
|
||||
/// New builder of function (signature & body)
|
||||
pub fn function() -> FunctionBuilder {
|
||||
FunctionBuilder::new()
|
||||
FunctionBuilder::new()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::{signatures, function};
|
||||
use elements;
|
||||
use super::{signatures, function};
|
||||
use elements;
|
||||
|
||||
#[test]
|
||||
fn example() {
|
||||
let result = signatures()
|
||||
.type_ref().val(1).build()
|
||||
.build();
|
||||
#[test]
|
||||
fn example() {
|
||||
let result = signatures()
|
||||
.type_ref().val(1).build()
|
||||
.build();
|
||||
|
||||
assert_eq!(result.entries().len(), 1);
|
||||
assert_eq!(result.entries().len(), 1);
|
||||
|
||||
let result = signatures()
|
||||
.signature()
|
||||
.param().i32()
|
||||
.param().i32()
|
||||
.return_type().i64()
|
||||
.build()
|
||||
.bind();
|
||||
let result = signatures()
|
||||
.signature()
|
||||
.param().i32()
|
||||
.param().i32()
|
||||
.return_type().i64()
|
||||
.build()
|
||||
.bind();
|
||||
|
||||
assert_eq!(result.len(), 1);
|
||||
}
|
||||
assert_eq!(result.len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn func_example() {
|
||||
let func = function()
|
||||
.signature()
|
||||
.param().i32()
|
||||
.return_type().i32()
|
||||
.build()
|
||||
.body()
|
||||
.with_opcodes(elements::Opcodes::empty())
|
||||
.build()
|
||||
.build();
|
||||
#[test]
|
||||
fn func_example() {
|
||||
let func = function()
|
||||
.signature()
|
||||
.param().i32()
|
||||
.return_type().i32()
|
||||
.build()
|
||||
.body()
|
||||
.with_opcodes(elements::Opcodes::empty())
|
||||
.build()
|
||||
.build();
|
||||
|
||||
assert_eq!(func.code.locals().len(), 0);
|
||||
assert_eq!(func.code.code().elements().len(), 1);
|
||||
}
|
||||
assert_eq!(func.code.locals().len(), 0);
|
||||
assert_eq!(func.code.code().elements().len(), 1);
|
||||
}
|
||||
}
|
@ -3,53 +3,53 @@ use elements;
|
||||
|
||||
/// Data segment builder
|
||||
pub struct DataSegmentBuilder<F=Identity> {
|
||||
callback: F,
|
||||
// todo: add mapper once multiple memory refs possible
|
||||
mem_index: u32,
|
||||
offset: elements::InitExpr,
|
||||
value: Vec<u8>,
|
||||
callback: F,
|
||||
// todo: add mapper once multiple memory refs possible
|
||||
mem_index: u32,
|
||||
offset: elements::InitExpr,
|
||||
value: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DataSegmentBuilder {
|
||||
/// New data segment builder
|
||||
pub fn new() -> Self {
|
||||
DataSegmentBuilder::with_callback(Identity)
|
||||
}
|
||||
/// New data segment builder
|
||||
pub fn new() -> Self {
|
||||
DataSegmentBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> DataSegmentBuilder<F> {
|
||||
/// New data segment builder inside the chain context
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
DataSegmentBuilder {
|
||||
callback: callback,
|
||||
mem_index: 0,
|
||||
offset: elements::InitExpr::empty(),
|
||||
value: Vec::new(),
|
||||
}
|
||||
}
|
||||
/// New data segment builder inside the chain context
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
DataSegmentBuilder {
|
||||
callback: callback,
|
||||
mem_index: 0,
|
||||
offset: elements::InitExpr::empty(),
|
||||
value: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set offset initialization opcode. `End` opcode will be added automatically.
|
||||
pub fn offset(mut self, opcode: elements::Opcode) -> Self {
|
||||
self.offset = elements::InitExpr::new(vec![opcode, elements::Opcode::End]);
|
||||
self
|
||||
}
|
||||
/// Set offset initialization opcode. `End` opcode will be added automatically.
|
||||
pub fn offset(mut self, opcode: elements::Opcode) -> Self {
|
||||
self.offset = elements::InitExpr::new(vec![opcode, elements::Opcode::End]);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the bytes value of the segment
|
||||
pub fn value(mut self, value: Vec<u8>) -> Self {
|
||||
self.value = value;
|
||||
self
|
||||
}
|
||||
/// Set the bytes value of the segment
|
||||
pub fn value(mut self, value: Vec<u8>) -> Self {
|
||||
self.value = value;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> DataSegmentBuilder<F> where F: Invoke<elements::DataSegment> {
|
||||
/// Finish current builder, spawning resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(
|
||||
elements::DataSegment::new(
|
||||
self.mem_index,
|
||||
self.offset,
|
||||
self.value,
|
||||
)
|
||||
)
|
||||
}
|
||||
/// Finish current builder, spawning resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(
|
||||
elements::DataSegment::new(
|
||||
self.mem_index,
|
||||
self.offset,
|
||||
self.value,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
@ -3,113 +3,113 @@ use elements;
|
||||
|
||||
/// Export entry builder
|
||||
pub struct ExportBuilder<F=Identity> {
|
||||
callback: F,
|
||||
field: String,
|
||||
binding: elements::Internal,
|
||||
callback: F,
|
||||
field: String,
|
||||
binding: elements::Internal,
|
||||
}
|
||||
|
||||
impl ExportBuilder {
|
||||
/// New export builder
|
||||
pub fn new() -> Self {
|
||||
ExportBuilder::with_callback(Identity)
|
||||
}
|
||||
/// New export builder
|
||||
pub fn new() -> Self {
|
||||
ExportBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> ExportBuilder<F> {
|
||||
|
||||
/// New export entry builder in the specified chained context
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ExportBuilder {
|
||||
callback: callback,
|
||||
field: String::new(),
|
||||
binding: elements::Internal::Function(0),
|
||||
}
|
||||
}
|
||||
/// New export entry builder in the specified chained context
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ExportBuilder {
|
||||
callback: callback,
|
||||
field: String::new(),
|
||||
binding: elements::Internal::Function(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the field name of the export entry
|
||||
pub fn field(mut self, field: &str) -> Self {
|
||||
self.field = field.to_owned();
|
||||
self
|
||||
}
|
||||
/// Set the field name of the export entry
|
||||
pub fn field(mut self, field: &str) -> Self {
|
||||
self.field = field.to_owned();
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify the internal module mapping for this entry
|
||||
pub fn with_internal(mut self, external: elements::Internal) -> Self {
|
||||
self.binding = external;
|
||||
self
|
||||
}
|
||||
/// Specify the internal module mapping for this entry
|
||||
pub fn with_internal(mut self, external: elements::Internal) -> Self {
|
||||
self.binding = external;
|
||||
self
|
||||
}
|
||||
|
||||
/// Start the internal builder for this export entry
|
||||
pub fn internal(self) -> ExportInternalBuilder<Self> {
|
||||
ExportInternalBuilder::with_callback(self)
|
||||
}
|
||||
/// Start the internal builder for this export entry
|
||||
pub fn internal(self) -> ExportInternalBuilder<Self> {
|
||||
ExportInternalBuilder::with_callback(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> ExportBuilder<F> where F: Invoke<elements::ExportEntry> {
|
||||
/// Finalize export entry builder spawning the resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(elements::ExportEntry::new(self.field, self.binding))
|
||||
}
|
||||
/// Finalize export entry builder spawning the resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(elements::ExportEntry::new(self.field, self.binding))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Invoke<elements::Internal> for ExportBuilder<F> {
|
||||
type Result = Self;
|
||||
fn invoke(self, val: elements::Internal) -> Self {
|
||||
self.with_internal(val)
|
||||
}
|
||||
type Result = Self;
|
||||
fn invoke(self, val: elements::Internal) -> Self {
|
||||
self.with_internal(val)
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal mapping builder for export entry
|
||||
pub struct ExportInternalBuilder<F=Identity> {
|
||||
callback: F,
|
||||
binding: elements::Internal,
|
||||
callback: F,
|
||||
binding: elements::Internal,
|
||||
}
|
||||
|
||||
impl<F> ExportInternalBuilder<F> where F: Invoke<elements::Internal> {
|
||||
/// New export entry internal mapping for the chained context
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ExportInternalBuilder{
|
||||
callback: callback,
|
||||
binding: elements::Internal::Function(0),
|
||||
}
|
||||
}
|
||||
/// New export entry internal mapping for the chained context
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ExportInternalBuilder{
|
||||
callback: callback,
|
||||
binding: elements::Internal::Function(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Map to function by index
|
||||
pub fn func(mut self, index: u32) -> F::Result {
|
||||
self.binding = elements::Internal::Function(index);
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
/// Map to function by index
|
||||
pub fn func(mut self, index: u32) -> F::Result {
|
||||
self.binding = elements::Internal::Function(index);
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
|
||||
/// Map to memory
|
||||
pub fn memory(mut self, index: u32) -> F::Result {
|
||||
self.binding = elements::Internal::Memory(index);
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
/// Map to memory
|
||||
pub fn memory(mut self, index: u32) -> F::Result {
|
||||
self.binding = elements::Internal::Memory(index);
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
|
||||
/// Map to table
|
||||
pub fn table(mut self, index: u32) -> F::Result {
|
||||
self.binding = elements::Internal::Table(index);
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
/// Map to table
|
||||
pub fn table(mut self, index: u32) -> F::Result {
|
||||
self.binding = elements::Internal::Table(index);
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
|
||||
/// Map to global
|
||||
pub fn global(mut self, index: u32) -> F::Result {
|
||||
self.binding = elements::Internal::Global(index);
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
/// Map to global
|
||||
pub fn global(mut self, index: u32) -> F::Result {
|
||||
self.binding = elements::Internal::Global(index);
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
}
|
||||
|
||||
/// New builder for export entry
|
||||
pub fn export() -> ExportBuilder {
|
||||
ExportBuilder::new()
|
||||
ExportBuilder::new()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::export;
|
||||
use super::export;
|
||||
|
||||
#[test]
|
||||
fn example() {
|
||||
let entry = export().field("memory").internal().memory(0).build();
|
||||
assert_eq!(entry.field(), "memory");
|
||||
}
|
||||
#[test]
|
||||
fn example() {
|
||||
let entry = export().field("memory").internal().memory(0).build();
|
||||
assert_eq!(entry.field(), "memory");
|
||||
}
|
||||
}
|
@ -4,87 +4,87 @@ use elements;
|
||||
|
||||
/// Global builder
|
||||
pub struct GlobalBuilder<F=Identity> {
|
||||
callback: F,
|
||||
value_type: elements::ValueType,
|
||||
is_mutable: bool,
|
||||
init_expr: elements::InitExpr,
|
||||
callback: F,
|
||||
value_type: elements::ValueType,
|
||||
is_mutable: bool,
|
||||
init_expr: elements::InitExpr,
|
||||
}
|
||||
|
||||
impl GlobalBuilder {
|
||||
/// New global builder
|
||||
pub fn new() -> Self {
|
||||
GlobalBuilder::with_callback(Identity)
|
||||
}
|
||||
/// New global builder
|
||||
pub fn new() -> Self {
|
||||
GlobalBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> GlobalBuilder<F> {
|
||||
/// New global builder with callback (in chained context)
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
GlobalBuilder {
|
||||
callback: callback,
|
||||
value_type: elements::ValueType::I32,
|
||||
init_expr: elements::InitExpr::empty(),
|
||||
is_mutable: false,
|
||||
}
|
||||
}
|
||||
/// New global builder with callback (in chained context)
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
GlobalBuilder {
|
||||
callback: callback,
|
||||
value_type: elements::ValueType::I32,
|
||||
init_expr: elements::InitExpr::empty(),
|
||||
is_mutable: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set/override resulting global type
|
||||
pub fn with_type(mut self, value_type: elements::ValueType) -> Self {
|
||||
self.value_type = value_type;
|
||||
self
|
||||
}
|
||||
/// Set/override resulting global type
|
||||
pub fn with_type(mut self, value_type: elements::ValueType) -> Self {
|
||||
self.value_type = value_type;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set mutabilty to true
|
||||
pub fn mutable(mut self) -> Self {
|
||||
self.is_mutable = true;
|
||||
self
|
||||
}
|
||||
/// Set mutabilty to true
|
||||
pub fn mutable(mut self) -> Self {
|
||||
self.is_mutable = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set initialization expression opcode for this global (`end` opcode will be added automatically)
|
||||
pub fn init_expr(mut self, opcode: elements::Opcode) -> Self {
|
||||
self.init_expr = elements::InitExpr::new(vec![opcode, elements::Opcode::End]);
|
||||
self
|
||||
}
|
||||
/// Set initialization expression opcode for this global (`end` opcode will be added automatically)
|
||||
pub fn init_expr(mut self, opcode: elements::Opcode) -> Self {
|
||||
self.init_expr = elements::InitExpr::new(vec![opcode, elements::Opcode::End]);
|
||||
self
|
||||
}
|
||||
|
||||
/// Start value type builder
|
||||
pub fn value_type(self) -> ValueTypeBuilder<Self> {
|
||||
ValueTypeBuilder::with_callback(self)
|
||||
}
|
||||
/// Start value type builder
|
||||
pub fn value_type(self) -> ValueTypeBuilder<Self> {
|
||||
ValueTypeBuilder::with_callback(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> GlobalBuilder<F> where F: Invoke<elements::GlobalEntry> {
|
||||
/// Finalize current builder spawning resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(
|
||||
elements::GlobalEntry::new(
|
||||
elements::GlobalType::new(self.value_type, self.is_mutable),
|
||||
self.init_expr,
|
||||
)
|
||||
)
|
||||
}
|
||||
/// Finalize current builder spawning resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(
|
||||
elements::GlobalEntry::new(
|
||||
elements::GlobalType::new(self.value_type, self.is_mutable),
|
||||
self.init_expr,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Invoke<elements::ValueType> for GlobalBuilder<F> {
|
||||
type Result = Self;
|
||||
fn invoke(self, the_type: elements::ValueType) -> Self {
|
||||
self.with_type(the_type)
|
||||
}
|
||||
type Result = Self;
|
||||
fn invoke(self, the_type: elements::ValueType) -> Self {
|
||||
self.with_type(the_type)
|
||||
}
|
||||
}
|
||||
|
||||
/// New builder for export entry
|
||||
pub fn global() -> GlobalBuilder {
|
||||
GlobalBuilder::new()
|
||||
GlobalBuilder::new()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::global;
|
||||
use elements;
|
||||
use super::global;
|
||||
use elements;
|
||||
|
||||
#[test]
|
||||
fn example() {
|
||||
let entry = global().value_type().i32().build();
|
||||
assert_eq!(entry.global_type().content_type(), elements::ValueType::I32);
|
||||
assert_eq!(entry.global_type().is_mutable(), false);
|
||||
}
|
||||
#[test]
|
||||
fn example() {
|
||||
let entry = global().value_type().i32().build();
|
||||
assert_eq!(entry.global_type().content_type(), elements::ValueType::I32);
|
||||
assert_eq!(entry.global_type().is_mutable(), false);
|
||||
}
|
||||
}
|
@ -3,127 +3,127 @@ use elements;
|
||||
|
||||
/// Import builder
|
||||
pub struct ImportBuilder<F=Identity> {
|
||||
callback: F,
|
||||
module: String,
|
||||
field: String,
|
||||
binding: elements::External,
|
||||
callback: F,
|
||||
module: String,
|
||||
field: String,
|
||||
binding: elements::External,
|
||||
}
|
||||
|
||||
impl ImportBuilder {
|
||||
/// New import builder
|
||||
pub fn new() -> Self {
|
||||
ImportBuilder::with_callback(Identity)
|
||||
}
|
||||
/// New import builder
|
||||
pub fn new() -> Self {
|
||||
ImportBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> ImportBuilder<F> {
|
||||
/// New import builder with callback (in chained context)
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ImportBuilder {
|
||||
callback: callback,
|
||||
module: String::new(),
|
||||
field: String::new(),
|
||||
binding: elements::External::Function(0),
|
||||
}
|
||||
}
|
||||
/// New import builder with callback (in chained context)
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ImportBuilder {
|
||||
callback: callback,
|
||||
module: String::new(),
|
||||
field: String::new(),
|
||||
binding: elements::External::Function(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set/override module name
|
||||
pub fn module(mut self, name: &str) -> Self {
|
||||
self.module = name.to_owned();
|
||||
self
|
||||
}
|
||||
/// Set/override module name
|
||||
pub fn module(mut self, name: &str) -> Self {
|
||||
self.module = name.to_owned();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set/override field name
|
||||
pub fn field(mut self, name: &str) -> Self {
|
||||
self.field = name.to_owned();
|
||||
self
|
||||
}
|
||||
/// Set/override field name
|
||||
pub fn field(mut self, name: &str) -> Self {
|
||||
self.field = name.to_owned();
|
||||
self
|
||||
}
|
||||
|
||||
/// Set/override both module name and field name
|
||||
pub fn path(self, module: &str, field: &str) -> Self {
|
||||
self.module(module).field(field)
|
||||
}
|
||||
/// Set/override both module name and field name
|
||||
pub fn path(self, module: &str, field: &str) -> Self {
|
||||
self.module(module).field(field)
|
||||
}
|
||||
|
||||
/// Set/override external mapping for this import
|
||||
pub fn with_external(mut self, external: elements::External) -> Self {
|
||||
self.binding = external;
|
||||
self
|
||||
}
|
||||
/// Set/override external mapping for this import
|
||||
pub fn with_external(mut self, external: elements::External) -> Self {
|
||||
self.binding = external;
|
||||
self
|
||||
}
|
||||
|
||||
/// Start new external mapping builder
|
||||
pub fn external(self) -> ImportExternalBuilder<Self> {
|
||||
ImportExternalBuilder::with_callback(self)
|
||||
}
|
||||
/// Start new external mapping builder
|
||||
pub fn external(self) -> ImportExternalBuilder<Self> {
|
||||
ImportExternalBuilder::with_callback(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> ImportBuilder<F> where F: Invoke<elements::ImportEntry> {
|
||||
/// Finalize current builder spawning the resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(elements::ImportEntry::new(self.module, self.field, self.binding))
|
||||
}
|
||||
/// Finalize current builder spawning the resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(elements::ImportEntry::new(self.module, self.field, self.binding))
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Invoke<elements::External> for ImportBuilder<F> {
|
||||
type Result = Self;
|
||||
fn invoke(self, val: elements::External) -> Self {
|
||||
self.with_external(val)
|
||||
}
|
||||
type Result = Self;
|
||||
fn invoke(self, val: elements::External) -> Self {
|
||||
self.with_external(val)
|
||||
}
|
||||
}
|
||||
|
||||
/// Import to external mapping builder
|
||||
pub struct ImportExternalBuilder<F=Identity> {
|
||||
callback: F,
|
||||
binding: elements::External,
|
||||
callback: F,
|
||||
binding: elements::External,
|
||||
}
|
||||
|
||||
impl<F> ImportExternalBuilder<F> where F: Invoke<elements::External> {
|
||||
/// New import to external mapping builder with callback (in chained context)
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ImportExternalBuilder{
|
||||
callback: callback,
|
||||
binding: elements::External::Function(0),
|
||||
}
|
||||
}
|
||||
/// New import to external mapping builder with callback (in chained context)
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ImportExternalBuilder{
|
||||
callback: callback,
|
||||
binding: elements::External::Function(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Function mapping with type reference
|
||||
pub fn func(mut self, index: u32) -> F::Result {
|
||||
self.binding = elements::External::Function(index);
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
/// Function mapping with type reference
|
||||
pub fn func(mut self, index: u32) -> F::Result {
|
||||
self.binding = elements::External::Function(index);
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
|
||||
/// Memory mapping with specified limits
|
||||
pub fn memory(mut self, min: u32, max: Option<u32>) -> F::Result {
|
||||
self.binding = elements::External::Memory(elements::MemoryType::new(min, max));
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
/// Memory mapping with specified limits
|
||||
pub fn memory(mut self, min: u32, max: Option<u32>) -> F::Result {
|
||||
self.binding = elements::External::Memory(elements::MemoryType::new(min, max));
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
|
||||
/// Table mapping with specified limits
|
||||
pub fn table(mut self, min: u32, max: Option<u32>) -> F::Result {
|
||||
self.binding = elements::External::Table(elements::TableType::new(min, max));
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
/// Table mapping with specified limits
|
||||
pub fn table(mut self, min: u32, max: Option<u32>) -> F::Result {
|
||||
self.binding = elements::External::Table(elements::TableType::new(min, max));
|
||||
self.callback.invoke(self.binding)
|
||||
}
|
||||
|
||||
/// Global mapping with speciifed type and mutability
|
||||
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.callback.invoke(self.binding)
|
||||
}
|
||||
/// Global mapping with speciifed type and mutability
|
||||
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.callback.invoke(self.binding)
|
||||
}
|
||||
}
|
||||
|
||||
/// New builder for import entry
|
||||
pub fn import() -> ImportBuilder {
|
||||
ImportBuilder::new()
|
||||
ImportBuilder::new()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::import;
|
||||
use super::import;
|
||||
|
||||
#[test]
|
||||
fn example() {
|
||||
let entry = import().module("env").field("memory").external().memory(256, Some(256)).build();
|
||||
#[test]
|
||||
fn example() {
|
||||
let entry = import().module("env").field("memory").external().memory(256, Some(256)).build();
|
||||
|
||||
assert_eq!(entry.module(), "env");
|
||||
assert_eq!(entry.field(), "memory");
|
||||
}
|
||||
assert_eq!(entry.module(), "env");
|
||||
assert_eq!(entry.field(), "memory");
|
||||
}
|
||||
}
|
@ -4,81 +4,81 @@ use super::invoke::{Invoke, Identity};
|
||||
/// Memory definition struct
|
||||
#[derive(Debug)]
|
||||
pub struct MemoryDefinition {
|
||||
/// Minimum memory size
|
||||
pub min: u32,
|
||||
/// Maximum memory size
|
||||
pub max: Option<u32>,
|
||||
/// Memory data segments (static regions)
|
||||
pub data: Vec<MemoryDataDefinition>,
|
||||
/// Minimum memory size
|
||||
pub min: u32,
|
||||
/// Maximum memory size
|
||||
pub max: Option<u32>,
|
||||
/// Memory data segments (static regions)
|
||||
pub data: Vec<MemoryDataDefinition>,
|
||||
}
|
||||
|
||||
/// Memory static region entry definition
|
||||
#[derive(Debug)]
|
||||
pub struct MemoryDataDefinition {
|
||||
/// Segment initialization expression for offset
|
||||
pub offset: elements::InitExpr,
|
||||
/// Raw bytes of static region
|
||||
pub values: Vec<u8>,
|
||||
/// Segment initialization expression for offset
|
||||
pub offset: elements::InitExpr,
|
||||
/// Raw bytes of static region
|
||||
pub values: Vec<u8>,
|
||||
}
|
||||
|
||||
/// Memory and static regions builder
|
||||
pub struct MemoryBuilder<F=Identity> {
|
||||
callback: F,
|
||||
memory: MemoryDefinition,
|
||||
callback: F,
|
||||
memory: MemoryDefinition,
|
||||
}
|
||||
|
||||
impl MemoryBuilder {
|
||||
/// New memory builder
|
||||
pub fn new() -> Self {
|
||||
MemoryBuilder::with_callback(Identity)
|
||||
}
|
||||
/// New memory builder
|
||||
pub fn new() -> Self {
|
||||
MemoryBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> MemoryBuilder<F> where F: Invoke<MemoryDefinition> {
|
||||
/// New memory builder with callback (in chained context)
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
MemoryBuilder {
|
||||
callback: callback,
|
||||
memory: Default::default(),
|
||||
}
|
||||
}
|
||||
/// New memory builder with callback (in chained context)
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
MemoryBuilder {
|
||||
callback: callback,
|
||||
memory: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set/override minimum size
|
||||
pub fn with_min(mut self, min: u32) -> Self {
|
||||
self.memory.min = min;
|
||||
self
|
||||
}
|
||||
/// Set/override minimum size
|
||||
pub fn with_min(mut self, min: u32) -> Self {
|
||||
self.memory.min = min;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set/override maximum size
|
||||
pub fn with_max(mut self, max: Option<u32>) -> Self {
|
||||
self.memory.max = max;
|
||||
self
|
||||
}
|
||||
/// Set/override maximum size
|
||||
pub fn with_max(mut self, max: Option<u32>) -> Self {
|
||||
self.memory.max = max;
|
||||
self
|
||||
}
|
||||
|
||||
/// Push new static region with initialized offset expression and raw bytes
|
||||
pub fn with_data(mut self, index: u32, values: Vec<u8>) -> Self {
|
||||
self.memory.data.push(MemoryDataDefinition {
|
||||
offset: elements::InitExpr::new(vec![
|
||||
elements::Opcode::I32Const(index as i32),
|
||||
elements::Opcode::End,
|
||||
]),
|
||||
values: values,
|
||||
});
|
||||
self
|
||||
}
|
||||
/// Push new static region with initialized offset expression and raw bytes
|
||||
pub fn with_data(mut self, index: u32, values: Vec<u8>) -> Self {
|
||||
self.memory.data.push(MemoryDataDefinition {
|
||||
offset: elements::InitExpr::new(vec![
|
||||
elements::Opcode::I32Const(index as i32),
|
||||
elements::Opcode::End,
|
||||
]),
|
||||
values: values,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Finalize current builder, spawning resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.memory)
|
||||
}
|
||||
/// Finalize current builder, spawning resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.memory)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MemoryDefinition {
|
||||
fn default() -> Self {
|
||||
MemoryDefinition {
|
||||
min: 1,
|
||||
max: None,
|
||||
data: Vec::new(),
|
||||
}
|
||||
}
|
||||
fn default() -> Self {
|
||||
MemoryDefinition {
|
||||
min: 1,
|
||||
max: None,
|
||||
data: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,91 +2,91 @@ use super::invoke::{Invoke, Identity};
|
||||
use elements;
|
||||
|
||||
pub struct ValueTypeBuilder<F=Identity> {
|
||||
callback: F,
|
||||
callback: F,
|
||||
}
|
||||
|
||||
impl<F> ValueTypeBuilder<F> where F: Invoke<elements::ValueType> {
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ValueTypeBuilder { callback: callback }
|
||||
}
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ValueTypeBuilder { callback: callback }
|
||||
}
|
||||
|
||||
pub fn i32(self) -> F::Result {
|
||||
self.callback.invoke(elements::ValueType::I32)
|
||||
}
|
||||
pub fn i32(self) -> F::Result {
|
||||
self.callback.invoke(elements::ValueType::I32)
|
||||
}
|
||||
|
||||
pub fn i64(self) -> F::Result {
|
||||
self.callback.invoke(elements::ValueType::I64)
|
||||
}
|
||||
pub fn i64(self) -> F::Result {
|
||||
self.callback.invoke(elements::ValueType::I64)
|
||||
}
|
||||
|
||||
pub fn f32(self) -> F::Result {
|
||||
self.callback.invoke(elements::ValueType::F32)
|
||||
}
|
||||
pub fn f32(self) -> F::Result {
|
||||
self.callback.invoke(elements::ValueType::F32)
|
||||
}
|
||||
|
||||
pub fn f64(self) -> F::Result {
|
||||
self.callback.invoke(elements::ValueType::F64)
|
||||
}
|
||||
pub fn f64(self) -> F::Result {
|
||||
self.callback.invoke(elements::ValueType::F64)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OptionalValueTypeBuilder<F=Identity> {
|
||||
callback: F,
|
||||
callback: F,
|
||||
}
|
||||
|
||||
impl<F> OptionalValueTypeBuilder<F> where F: Invoke<Option<elements::ValueType>> {
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
OptionalValueTypeBuilder { callback: callback }
|
||||
}
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
OptionalValueTypeBuilder { callback: callback }
|
||||
}
|
||||
|
||||
pub fn i32(self) -> F::Result {
|
||||
self.callback.invoke(Some(elements::ValueType::I32))
|
||||
}
|
||||
pub fn i32(self) -> F::Result {
|
||||
self.callback.invoke(Some(elements::ValueType::I32))
|
||||
}
|
||||
|
||||
pub fn i64(self) -> F::Result {
|
||||
self.callback.invoke(Some(elements::ValueType::I64))
|
||||
}
|
||||
pub fn i64(self) -> F::Result {
|
||||
self.callback.invoke(Some(elements::ValueType::I64))
|
||||
}
|
||||
|
||||
pub fn f32(self) -> F::Result {
|
||||
self.callback.invoke(Some(elements::ValueType::F32))
|
||||
}
|
||||
pub fn f32(self) -> F::Result {
|
||||
self.callback.invoke(Some(elements::ValueType::F32))
|
||||
}
|
||||
|
||||
pub fn f64(self) -> F::Result {
|
||||
self.callback.invoke(Some(elements::ValueType::F64))
|
||||
}
|
||||
pub fn f64(self) -> F::Result {
|
||||
self.callback.invoke(Some(elements::ValueType::F64))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ValueTypesBuilder<F=Identity> {
|
||||
callback: F,
|
||||
value_types: Vec<elements::ValueType>,
|
||||
callback: F,
|
||||
value_types: Vec<elements::ValueType>,
|
||||
}
|
||||
|
||||
impl<F> ValueTypesBuilder<F> where F: Invoke<Vec<elements::ValueType>> {
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ValueTypesBuilder {
|
||||
callback: callback,
|
||||
value_types: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ValueTypesBuilder {
|
||||
callback: callback,
|
||||
value_types: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn i32(mut self) -> Self {
|
||||
self.value_types.push(elements::ValueType::I32);
|
||||
self
|
||||
}
|
||||
pub fn i32(mut self) -> Self {
|
||||
self.value_types.push(elements::ValueType::I32);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn i64(mut self) -> Self {
|
||||
self.value_types.push(elements::ValueType::I64);
|
||||
self
|
||||
}
|
||||
pub fn i64(mut self) -> Self {
|
||||
self.value_types.push(elements::ValueType::I64);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn f32(mut self) -> Self {
|
||||
self.value_types.push(elements::ValueType::F32);
|
||||
self
|
||||
}
|
||||
pub fn f32(mut self) -> Self {
|
||||
self.value_types.push(elements::ValueType::F32);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn f64(mut self) -> Self {
|
||||
self.value_types.push(elements::ValueType::F64);
|
||||
self
|
||||
}
|
||||
pub fn f64(mut self) -> Self {
|
||||
self.value_types.push(elements::ValueType::F64);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.value_types)
|
||||
}
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.value_types)
|
||||
}
|
||||
}
|
@ -12,8 +12,8 @@ mod global;
|
||||
mod data;
|
||||
|
||||
pub use self::code::{
|
||||
signatures, signature, function, SignatureBuilder, SignaturesBuilder,
|
||||
FunctionBuilder, TypeRefBuilder, FuncBodyBuilder, FunctionDefinition,
|
||||
signatures, signature, function, SignatureBuilder, SignaturesBuilder,
|
||||
FunctionBuilder, TypeRefBuilder, FuncBodyBuilder, FunctionDefinition,
|
||||
};
|
||||
pub use self::data::DataSegmentBuilder;
|
||||
pub use self::export::{export, ExportBuilder, ExportInternalBuilder};
|
||||
|
@ -7,484 +7,484 @@ use elements;
|
||||
|
||||
/// Module builder
|
||||
pub struct ModuleBuilder<F=Identity> {
|
||||
callback: F,
|
||||
module: ModuleScaffold,
|
||||
callback: F,
|
||||
module: ModuleScaffold,
|
||||
}
|
||||
|
||||
/// Location of the internal module function
|
||||
pub struct CodeLocation {
|
||||
/// Location (index in 'functions' section) of the signature
|
||||
pub signature: u32,
|
||||
/// Location (index in the 'code' section) of the body
|
||||
pub body: u32,
|
||||
/// Location (index in 'functions' section) of the signature
|
||||
pub signature: u32,
|
||||
/// Location (index in the 'code' section) of the body
|
||||
pub body: u32,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ModuleScaffold {
|
||||
pub types: elements::TypeSection,
|
||||
pub import: elements::ImportSection,
|
||||
pub functions: elements::FunctionSection,
|
||||
pub table: elements::TableSection,
|
||||
pub memory: elements::MemorySection,
|
||||
pub global: elements::GlobalSection,
|
||||
pub export: elements::ExportSection,
|
||||
pub start: Option<u32>,
|
||||
pub element: elements::ElementSection,
|
||||
pub code: elements::CodeSection,
|
||||
pub data: elements::DataSection,
|
||||
pub other: Vec<elements::Section>,
|
||||
pub types: elements::TypeSection,
|
||||
pub import: elements::ImportSection,
|
||||
pub functions: elements::FunctionSection,
|
||||
pub table: elements::TableSection,
|
||||
pub memory: elements::MemorySection,
|
||||
pub global: elements::GlobalSection,
|
||||
pub export: elements::ExportSection,
|
||||
pub start: Option<u32>,
|
||||
pub element: elements::ElementSection,
|
||||
pub code: elements::CodeSection,
|
||||
pub data: elements::DataSection,
|
||||
pub other: Vec<elements::Section>,
|
||||
}
|
||||
|
||||
impl From<elements::Module> for ModuleScaffold {
|
||||
fn from(module: elements::Module) -> Self {
|
||||
let mut types: Option<elements::TypeSection> = None;
|
||||
let mut import: Option<elements::ImportSection> = None;
|
||||
let mut funcs: Option<elements::FunctionSection> = None;
|
||||
let mut table: Option<elements::TableSection> = None;
|
||||
let mut memory: Option<elements::MemorySection> = None;
|
||||
let mut global: Option<elements::GlobalSection> = None;
|
||||
let mut export: Option<elements::ExportSection> = None;
|
||||
let mut start: Option<u32> = None;
|
||||
let mut element: Option<elements::ElementSection> = None;
|
||||
let mut code: Option<elements::CodeSection> = None;
|
||||
let mut data: Option<elements::DataSection> = None;
|
||||
fn from(module: elements::Module) -> Self {
|
||||
let mut types: Option<elements::TypeSection> = None;
|
||||
let mut import: Option<elements::ImportSection> = None;
|
||||
let mut funcs: Option<elements::FunctionSection> = None;
|
||||
let mut table: Option<elements::TableSection> = None;
|
||||
let mut memory: Option<elements::MemorySection> = None;
|
||||
let mut global: Option<elements::GlobalSection> = None;
|
||||
let mut export: Option<elements::ExportSection> = None;
|
||||
let mut start: Option<u32> = None;
|
||||
let mut element: Option<elements::ElementSection> = None;
|
||||
let mut code: Option<elements::CodeSection> = None;
|
||||
let mut data: Option<elements::DataSection> = None;
|
||||
|
||||
let mut sections = module.into_sections();
|
||||
while let Some(section) = sections.pop() {
|
||||
match section {
|
||||
elements::Section::Type(sect) => { types = Some(sect); }
|
||||
elements::Section::Import(sect) => { import = Some(sect); }
|
||||
elements::Section::Function(sect) => { funcs = Some(sect); }
|
||||
elements::Section::Table(sect) => { table = Some(sect); }
|
||||
elements::Section::Memory(sect) => { memory = Some(sect); }
|
||||
elements::Section::Global(sect) => { global = Some(sect); }
|
||||
elements::Section::Export(sect) => { export = Some(sect); }
|
||||
elements::Section::Start(index) => { start = Some(index); }
|
||||
elements::Section::Element(sect) => { element = Some(sect); }
|
||||
elements::Section::Code(sect) => { code = Some(sect); }
|
||||
elements::Section::Data(sect) => { data = Some(sect); }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
let mut sections = module.into_sections();
|
||||
while let Some(section) = sections.pop() {
|
||||
match section {
|
||||
elements::Section::Type(sect) => { types = Some(sect); }
|
||||
elements::Section::Import(sect) => { import = Some(sect); }
|
||||
elements::Section::Function(sect) => { funcs = Some(sect); }
|
||||
elements::Section::Table(sect) => { table = Some(sect); }
|
||||
elements::Section::Memory(sect) => { memory = Some(sect); }
|
||||
elements::Section::Global(sect) => { global = Some(sect); }
|
||||
elements::Section::Export(sect) => { export = Some(sect); }
|
||||
elements::Section::Start(index) => { start = Some(index); }
|
||||
elements::Section::Element(sect) => { element = Some(sect); }
|
||||
elements::Section::Code(sect) => { code = Some(sect); }
|
||||
elements::Section::Data(sect) => { data = Some(sect); }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
ModuleScaffold {
|
||||
types: types.unwrap_or_default(),
|
||||
import: import.unwrap_or_default(),
|
||||
functions: funcs.unwrap_or_default(),
|
||||
table: table.unwrap_or_default(),
|
||||
memory: memory.unwrap_or_default(),
|
||||
global: global.unwrap_or_default(),
|
||||
export: export.unwrap_or_default(),
|
||||
start: start,
|
||||
element: element.unwrap_or_default(),
|
||||
code: code.unwrap_or_default(),
|
||||
data: data.unwrap_or_default(),
|
||||
other: sections,
|
||||
}
|
||||
}
|
||||
ModuleScaffold {
|
||||
types: types.unwrap_or_default(),
|
||||
import: import.unwrap_or_default(),
|
||||
functions: funcs.unwrap_or_default(),
|
||||
table: table.unwrap_or_default(),
|
||||
memory: memory.unwrap_or_default(),
|
||||
global: global.unwrap_or_default(),
|
||||
export: export.unwrap_or_default(),
|
||||
start: start,
|
||||
element: element.unwrap_or_default(),
|
||||
code: code.unwrap_or_default(),
|
||||
data: data.unwrap_or_default(),
|
||||
other: sections,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ModuleScaffold> for elements::Module {
|
||||
fn from(module: ModuleScaffold) -> Self {
|
||||
let mut sections = Vec::new();
|
||||
fn from(module: ModuleScaffold) -> Self {
|
||||
let mut sections = Vec::new();
|
||||
|
||||
let types = module.types;
|
||||
if types.types().len() > 0 {
|
||||
sections.push(elements::Section::Type(types));
|
||||
}
|
||||
let import = module.import;
|
||||
if import.entries().len() > 0 {
|
||||
sections.push(elements::Section::Import(import));
|
||||
}
|
||||
let functions = module.functions;
|
||||
if functions.entries().len() > 0 {
|
||||
sections.push(elements::Section::Function(functions));
|
||||
}
|
||||
let table = module.table;
|
||||
if table.entries().len() > 0 {
|
||||
sections.push(elements::Section::Table(table));
|
||||
}
|
||||
let memory = module.memory;
|
||||
if memory.entries().len() > 0 {
|
||||
sections.push(elements::Section::Memory(memory));
|
||||
}
|
||||
let global = module.global;
|
||||
if global.entries().len() > 0 {
|
||||
sections.push(elements::Section::Global(global));
|
||||
}
|
||||
let export = module.export;
|
||||
if export.entries().len() > 0 {
|
||||
sections.push(elements::Section::Export(export));
|
||||
}
|
||||
if let Some(start) = module.start {
|
||||
sections.push(elements::Section::Start(start));
|
||||
}
|
||||
let element = module.element;
|
||||
if element.entries().len() > 0 {
|
||||
sections.push(elements::Section::Element(element));
|
||||
}
|
||||
let code = module.code;
|
||||
if code.bodies().len() > 0 {
|
||||
sections.push(elements::Section::Code(code));
|
||||
}
|
||||
let data = module.data;
|
||||
if data.entries().len() > 0 {
|
||||
sections.push(elements::Section::Data(data));
|
||||
}
|
||||
sections.extend(module.other);
|
||||
elements::Module::new(sections)
|
||||
}
|
||||
let types = module.types;
|
||||
if types.types().len() > 0 {
|
||||
sections.push(elements::Section::Type(types));
|
||||
}
|
||||
let import = module.import;
|
||||
if import.entries().len() > 0 {
|
||||
sections.push(elements::Section::Import(import));
|
||||
}
|
||||
let functions = module.functions;
|
||||
if functions.entries().len() > 0 {
|
||||
sections.push(elements::Section::Function(functions));
|
||||
}
|
||||
let table = module.table;
|
||||
if table.entries().len() > 0 {
|
||||
sections.push(elements::Section::Table(table));
|
||||
}
|
||||
let memory = module.memory;
|
||||
if memory.entries().len() > 0 {
|
||||
sections.push(elements::Section::Memory(memory));
|
||||
}
|
||||
let global = module.global;
|
||||
if global.entries().len() > 0 {
|
||||
sections.push(elements::Section::Global(global));
|
||||
}
|
||||
let export = module.export;
|
||||
if export.entries().len() > 0 {
|
||||
sections.push(elements::Section::Export(export));
|
||||
}
|
||||
if let Some(start) = module.start {
|
||||
sections.push(elements::Section::Start(start));
|
||||
}
|
||||
let element = module.element;
|
||||
if element.entries().len() > 0 {
|
||||
sections.push(elements::Section::Element(element));
|
||||
}
|
||||
let code = module.code;
|
||||
if code.bodies().len() > 0 {
|
||||
sections.push(elements::Section::Code(code));
|
||||
}
|
||||
let data = module.data;
|
||||
if data.entries().len() > 0 {
|
||||
sections.push(elements::Section::Data(data));
|
||||
}
|
||||
sections.extend(module.other);
|
||||
elements::Module::new(sections)
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleBuilder {
|
||||
/// New empty module builder
|
||||
pub fn new() -> Self {
|
||||
ModuleBuilder::with_callback(Identity)
|
||||
}
|
||||
/// New empty module builder
|
||||
pub fn new() -> Self {
|
||||
ModuleBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
|
||||
/// New module builder with bound callback
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ModuleBuilder {
|
||||
callback: callback,
|
||||
module: Default::default(),
|
||||
}
|
||||
}
|
||||
/// New module builder with bound callback
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
ModuleBuilder {
|
||||
callback: callback,
|
||||
module: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder from raw module
|
||||
pub fn with_module(mut self, module: elements::Module) -> Self {
|
||||
self.module = module.into();
|
||||
self
|
||||
}
|
||||
/// Builder from raw module
|
||||
pub fn with_module(mut self, module: elements::Module) -> Self {
|
||||
self.module = module.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Fill module with sections from iterator
|
||||
pub fn with_sections<I>(mut self, sections: I) -> Self
|
||||
where I: IntoIterator<Item=elements::Section>
|
||||
{
|
||||
self.module.other.extend(sections);
|
||||
self
|
||||
}
|
||||
/// Fill module with sections from iterator
|
||||
pub fn with_sections<I>(mut self, sections: I) -> Self
|
||||
where I: IntoIterator<Item=elements::Section>
|
||||
{
|
||||
self.module.other.extend(sections);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add additional section
|
||||
pub fn with_section(mut self, section: elements::Section) -> Self {
|
||||
self.module.other.push(section);
|
||||
self
|
||||
}
|
||||
/// Add additional section
|
||||
pub fn with_section(mut self, section: elements::Section) -> Self {
|
||||
self.module.other.push(section);
|
||||
self
|
||||
}
|
||||
|
||||
/// Binds to the type section, creates additional types when required
|
||||
pub fn with_signatures(mut self, bindings: code::SignatureBindings) -> Self {
|
||||
self.push_signatures(bindings);
|
||||
self
|
||||
}
|
||||
/// Binds to the type section, creates additional types when required
|
||||
pub fn with_signatures(mut self, bindings: code::SignatureBindings) -> Self {
|
||||
self.push_signatures(bindings);
|
||||
self
|
||||
}
|
||||
|
||||
/// Push stand-alone function definition, creating sections, signature and code blocks
|
||||
/// in corresponding sections.
|
||||
/// `FunctionDefinition` can be build using `builder::function` builder
|
||||
pub fn push_function(&mut self, func: code::FunctionDefinition) -> CodeLocation {
|
||||
let signature = func.signature;
|
||||
let body = func.code;
|
||||
/// Push stand-alone function definition, creating sections, signature and code blocks
|
||||
/// in corresponding sections.
|
||||
/// `FunctionDefinition` can be build using `builder::function` builder
|
||||
pub fn push_function(&mut self, func: code::FunctionDefinition) -> CodeLocation {
|
||||
let signature = func.signature;
|
||||
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));
|
||||
let signature_index = self.module.functions.entries_mut().len() as u32 - 1;
|
||||
self.module.code.bodies_mut().push(body);
|
||||
let body_index = self.module.code.bodies_mut().len() as u32 - 1;
|
||||
self.module.functions.entries_mut().push(elements::Func::new(type_ref));
|
||||
let signature_index = self.module.functions.entries_mut().len() as u32 - 1;
|
||||
self.module.code.bodies_mut().push(body);
|
||||
let body_index = self.module.code.bodies_mut().len() as u32 - 1;
|
||||
|
||||
if func.is_main {
|
||||
self.module.start = Some(body_index);
|
||||
}
|
||||
if func.is_main {
|
||||
self.module.start = Some(body_index);
|
||||
}
|
||||
|
||||
CodeLocation {
|
||||
signature: signature_index,
|
||||
body: body_index,
|
||||
}
|
||||
}
|
||||
CodeLocation {
|
||||
signature: signature_index,
|
||||
body: body_index,
|
||||
}
|
||||
}
|
||||
|
||||
/// Push linear memory region
|
||||
pub fn push_memory(&mut self, mut memory: memory::MemoryDefinition) -> u32 {
|
||||
let entries = self.module.memory.entries_mut();
|
||||
entries.push(elements::MemoryType::new(memory.min, memory.max));
|
||||
let memory_index = (entries.len() - 1) as u32;
|
||||
for data in memory.data.drain(..) {
|
||||
self.module.data.entries_mut()
|
||||
.push(elements::DataSegment::new(memory_index, data.offset, data.values))
|
||||
}
|
||||
memory_index
|
||||
}
|
||||
/// Push linear memory region
|
||||
pub fn push_memory(&mut self, mut memory: memory::MemoryDefinition) -> u32 {
|
||||
let entries = self.module.memory.entries_mut();
|
||||
entries.push(elements::MemoryType::new(memory.min, memory.max));
|
||||
let memory_index = (entries.len() - 1) as u32;
|
||||
for data in memory.data.drain(..) {
|
||||
self.module.data.entries_mut()
|
||||
.push(elements::DataSegment::new(memory_index, data.offset, data.values))
|
||||
}
|
||||
memory_index
|
||||
}
|
||||
|
||||
/// Push table
|
||||
pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 {
|
||||
let entries = self.module.table.entries_mut();
|
||||
entries.push(elements::TableType::new(table.min, table.max));
|
||||
let table_index = (entries.len() - 1) as u32;
|
||||
for entry in table.elements.drain(..) {
|
||||
self.module.element.entries_mut()
|
||||
.push(elements::ElementSegment::new(table_index, entry.offset, entry.values))
|
||||
}
|
||||
table_index
|
||||
}
|
||||
/// Push table
|
||||
pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 {
|
||||
let entries = self.module.table.entries_mut();
|
||||
entries.push(elements::TableType::new(table.min, table.max));
|
||||
let table_index = (entries.len() - 1) as u32;
|
||||
for entry in table.elements.drain(..) {
|
||||
self.module.element.entries_mut()
|
||||
.push(elements::ElementSegment::new(table_index, entry.offset, entry.values))
|
||||
}
|
||||
table_index
|
||||
}
|
||||
|
||||
fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 {
|
||||
match signature {
|
||||
code::Signature::Inline(func_type) => {
|
||||
// todo: maybe search for existing type
|
||||
self.module.types.types_mut().push(elements::Type::Function(func_type));
|
||||
self.module.types.types().len() as u32 - 1
|
||||
}
|
||||
code::Signature::TypeReference(type_ref) => {
|
||||
type_ref
|
||||
}
|
||||
}
|
||||
}
|
||||
fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 {
|
||||
match signature {
|
||||
code::Signature::Inline(func_type) => {
|
||||
// todo: maybe search for existing type
|
||||
self.module.types.types_mut().push(elements::Type::Function(func_type));
|
||||
self.module.types.types().len() as u32 - 1
|
||||
}
|
||||
code::Signature::TypeReference(type_ref) => {
|
||||
type_ref
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Push one function signature, returning it's calling index.
|
||||
/// Can create corresponding type in type section.
|
||||
pub fn push_signature(&mut self, signature: code::Signature) -> u32 {
|
||||
self.resolve_type_ref(signature)
|
||||
}
|
||||
/// Push one function signature, returning it's calling index.
|
||||
/// Can create corresponding type in type section.
|
||||
pub fn push_signature(&mut self, signature: code::Signature) -> u32 {
|
||||
self.resolve_type_ref(signature)
|
||||
}
|
||||
|
||||
/// Push signatures in the module, returning corresponding indices of pushed signatures
|
||||
pub fn push_signatures(&mut self, signatures: code::SignatureBindings) -> Vec<u32> {
|
||||
signatures.into_iter().map(|binding|
|
||||
self.resolve_type_ref(binding)
|
||||
).collect()
|
||||
}
|
||||
/// Push signatures in the module, returning corresponding indices of pushed signatures
|
||||
pub fn push_signatures(&mut self, signatures: code::SignatureBindings) -> Vec<u32> {
|
||||
signatures.into_iter().map(|binding|
|
||||
self.resolve_type_ref(binding)
|
||||
).collect()
|
||||
}
|
||||
|
||||
/// Push import entry to module. Not that it does not update calling indices in
|
||||
/// function bodies.
|
||||
pub fn push_import(&mut self, import: elements::ImportEntry) -> u32 {
|
||||
self.module.import.entries_mut().push(import);
|
||||
// todo: actually update calling addresses in function bodies
|
||||
// todo: also batch push
|
||||
/// Push import entry to module. Not that it does not update calling indices in
|
||||
/// function bodies.
|
||||
pub fn push_import(&mut self, import: elements::ImportEntry) -> u32 {
|
||||
self.module.import.entries_mut().push(import);
|
||||
// todo: actually update calling addresses in function bodies
|
||||
// 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.
|
||||
pub fn push_export(&mut self, export: elements::ExportEntry) -> u32 {
|
||||
self.module.export.entries_mut().push(export);
|
||||
self.module.export.entries_mut().len() as u32 - 1
|
||||
}
|
||||
/// Push export entry to module.
|
||||
pub fn push_export(&mut self, export: elements::ExportEntry) -> u32 {
|
||||
self.module.export.entries_mut().push(export);
|
||||
self.module.export.entries_mut().len() as u32 - 1
|
||||
}
|
||||
|
||||
/// Add new function using dedicated builder
|
||||
pub fn function(self) -> FunctionBuilder<Self> {
|
||||
FunctionBuilder::with_callback(self)
|
||||
}
|
||||
/// Add new function using dedicated builder
|
||||
pub fn function(self) -> FunctionBuilder<Self> {
|
||||
FunctionBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Add new linear memory using dedicated builder
|
||||
pub fn memory(self) -> MemoryBuilder<Self> {
|
||||
MemoryBuilder::with_callback(self)
|
||||
}
|
||||
/// Add new linear memory using dedicated builder
|
||||
pub fn memory(self) -> MemoryBuilder<Self> {
|
||||
MemoryBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Add new table using dedicated builder
|
||||
pub fn table(self) -> TableBuilder<Self> {
|
||||
TableBuilder::with_callback(self)
|
||||
}
|
||||
/// Add new table using dedicated builder
|
||||
pub fn table(self) -> TableBuilder<Self> {
|
||||
TableBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Define functions section
|
||||
pub fn functions(self) -> SignaturesBuilder<Self> {
|
||||
SignaturesBuilder::with_callback(self)
|
||||
}
|
||||
/// Define functions section
|
||||
pub fn functions(self) -> SignaturesBuilder<Self> {
|
||||
SignaturesBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// With inserted export entry
|
||||
pub fn with_export(mut self, entry: elements::ExportEntry) -> Self {
|
||||
self.module.export.entries_mut().push(entry);
|
||||
self
|
||||
}
|
||||
/// With inserted export entry
|
||||
pub fn with_export(mut self, entry: elements::ExportEntry) -> Self {
|
||||
self.module.export.entries_mut().push(entry);
|
||||
self
|
||||
}
|
||||
|
||||
/// With inserted import entry
|
||||
pub fn with_import(mut self, entry: elements::ImportEntry) -> Self {
|
||||
self.module.import.entries_mut().push(entry);
|
||||
self
|
||||
}
|
||||
/// With inserted import entry
|
||||
pub fn with_import(mut self, entry: elements::ImportEntry) -> Self {
|
||||
self.module.import.entries_mut().push(entry);
|
||||
self
|
||||
}
|
||||
|
||||
/// Import entry builder
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use parity_wasm::builder::module;
|
||||
///
|
||||
/// let module = module()
|
||||
/// .import()
|
||||
/// .module("env")
|
||||
/// .field("memory")
|
||||
/// .external().memory(256, Some(256))
|
||||
/// .build()
|
||||
/// .build();
|
||||
///
|
||||
/// assert_eq!(module.import_section().expect("import section to exist").entries().len(), 1);
|
||||
/// ```
|
||||
pub fn import(self) -> import::ImportBuilder<Self> {
|
||||
import::ImportBuilder::with_callback(self)
|
||||
}
|
||||
/// Import entry builder
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use parity_wasm::builder::module;
|
||||
///
|
||||
/// let module = module()
|
||||
/// .import()
|
||||
/// .module("env")
|
||||
/// .field("memory")
|
||||
/// .external().memory(256, Some(256))
|
||||
/// .build()
|
||||
/// .build();
|
||||
///
|
||||
/// assert_eq!(module.import_section().expect("import section to exist").entries().len(), 1);
|
||||
/// ```
|
||||
pub fn import(self) -> import::ImportBuilder<Self> {
|
||||
import::ImportBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// With global variable
|
||||
pub fn with_global(mut self, global: elements::GlobalEntry) -> Self {
|
||||
self.module.global.entries_mut().push(global);
|
||||
self
|
||||
}
|
||||
/// With global variable
|
||||
pub fn with_global(mut self, global: elements::GlobalEntry) -> Self {
|
||||
self.module.global.entries_mut().push(global);
|
||||
self
|
||||
}
|
||||
|
||||
/// With table
|
||||
pub fn with_table(mut self, table: elements::TableType) -> Self {
|
||||
self.module.table.entries_mut().push(table);
|
||||
self
|
||||
}
|
||||
/// With table
|
||||
pub fn with_table(mut self, table: elements::TableType) -> Self {
|
||||
self.module.table.entries_mut().push(table);
|
||||
self
|
||||
}
|
||||
|
||||
/// Export entry builder
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use parity_wasm::builder::module;
|
||||
/// use parity_wasm::elements::Opcode::*;
|
||||
///
|
||||
/// let module = module()
|
||||
/// .global()
|
||||
/// .value_type().i32()
|
||||
/// .init_expr(I32Const(0))
|
||||
/// .build()
|
||||
/// .export()
|
||||
/// .field("_zero")
|
||||
/// .internal().global(0)
|
||||
/// .build()
|
||||
/// .build();
|
||||
///
|
||||
/// assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1);
|
||||
/// ```
|
||||
pub fn export(self) -> export::ExportBuilder<Self> {
|
||||
export::ExportBuilder::with_callback(self)
|
||||
}
|
||||
/// Export entry builder
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use parity_wasm::builder::module;
|
||||
/// use parity_wasm::elements::Opcode::*;
|
||||
///
|
||||
/// let module = module()
|
||||
/// .global()
|
||||
/// .value_type().i32()
|
||||
/// .init_expr(I32Const(0))
|
||||
/// .build()
|
||||
/// .export()
|
||||
/// .field("_zero")
|
||||
/// .internal().global(0)
|
||||
/// .build()
|
||||
/// .build();
|
||||
///
|
||||
/// assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1);
|
||||
/// ```
|
||||
pub fn export(self) -> export::ExportBuilder<Self> {
|
||||
export::ExportBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Glboal entry builder
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use parity_wasm::builder::module;
|
||||
/// use parity_wasm::elements::Opcode::*;
|
||||
///
|
||||
/// let module = module()
|
||||
/// .global()
|
||||
/// .value_type().i32()
|
||||
/// .init_expr(I32Const(0))
|
||||
/// .build()
|
||||
/// .build();
|
||||
///
|
||||
/// assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1);
|
||||
/// ```
|
||||
pub fn global(self) -> global::GlobalBuilder<Self> {
|
||||
global::GlobalBuilder::with_callback(self)
|
||||
}
|
||||
/// Glboal entry builder
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use parity_wasm::builder::module;
|
||||
/// use parity_wasm::elements::Opcode::*;
|
||||
///
|
||||
/// let module = module()
|
||||
/// .global()
|
||||
/// .value_type().i32()
|
||||
/// .init_expr(I32Const(0))
|
||||
/// .build()
|
||||
/// .build();
|
||||
///
|
||||
/// assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1);
|
||||
/// ```
|
||||
pub fn global(self) -> global::GlobalBuilder<Self> {
|
||||
global::GlobalBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Add data segment to the builder
|
||||
pub fn with_data_segment(mut self, segment: elements::DataSegment) -> Self {
|
||||
self.module.data.entries_mut().push(segment);
|
||||
self
|
||||
}
|
||||
/// Add data segment to the builder
|
||||
pub fn with_data_segment(mut self, segment: elements::DataSegment) -> Self {
|
||||
self.module.data.entries_mut().push(segment);
|
||||
self
|
||||
}
|
||||
|
||||
/// Data entry builder
|
||||
pub fn data(self) -> data::DataSegmentBuilder<Self> {
|
||||
data::DataSegmentBuilder::with_callback(self)
|
||||
}
|
||||
/// Data entry builder
|
||||
pub fn data(self) -> data::DataSegmentBuilder<Self> {
|
||||
data::DataSegmentBuilder::with_callback(self)
|
||||
}
|
||||
|
||||
/// Build module (final step)
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.module.into())
|
||||
}
|
||||
/// Build module (final step)
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.module.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Invoke<elements::FunctionSection> for ModuleBuilder<F>
|
||||
where F: Invoke<elements::Module>
|
||||
impl<F> Invoke<elements::FunctionSection> for ModuleBuilder<F>
|
||||
where F: Invoke<elements::Module>
|
||||
{
|
||||
type Result = Self;
|
||||
|
||||
fn invoke(self, section: elements::FunctionSection) -> Self {
|
||||
self.with_section(elements::Section::Function(section))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_signatures(bindings)
|
||||
}
|
||||
fn invoke(self, bindings: code::SignatureBindings) -> Self {
|
||||
self.with_signatures(bindings)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
let mut b = self;
|
||||
b.push_function(def);
|
||||
b
|
||||
}
|
||||
fn invoke(self, def: code::FunctionDefinition) -> Self {
|
||||
let mut b = self;
|
||||
b.push_function(def);
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
let mut b = self;
|
||||
b.push_memory(def);
|
||||
b
|
||||
}
|
||||
fn invoke(self, def: memory::MemoryDefinition) -> Self {
|
||||
let mut b = self;
|
||||
b.push_memory(def);
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
let mut b = self;
|
||||
b.push_table(def);
|
||||
b
|
||||
}
|
||||
fn invoke(self, def: table::TableDefinition) -> Self {
|
||||
let mut b = self;
|
||||
b.push_table(def);
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_import(entry)
|
||||
}
|
||||
fn invoke(self, entry: elements::ImportEntry) -> Self::Result {
|
||||
self.with_import(entry)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_export(entry)
|
||||
}
|
||||
fn invoke(self, entry: elements::ExportEntry) -> Self::Result {
|
||||
self.with_export(entry)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
self.with_global(entry)
|
||||
}
|
||||
fn invoke(self, entry: elements::GlobalEntry) -> Self::Result {
|
||||
self.with_global(entry)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F>
|
||||
where F: Invoke<elements::Module>
|
||||
impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F>
|
||||
where F: Invoke<elements::Module>
|
||||
{
|
||||
type Result = Self;
|
||||
|
||||
fn invoke(self, segment: elements::DataSegment) -> Self {
|
||||
self.with_data_segment(segment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Start new module builder
|
||||
@ -492,7 +492,7 @@ impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F>
|
||||
///
|
||||
/// ```
|
||||
/// use parity_wasm::builder;
|
||||
///
|
||||
///
|
||||
/// let module = builder::module()
|
||||
/// .function()
|
||||
/// .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);
|
||||
/// ```
|
||||
pub fn module() -> ModuleBuilder {
|
||||
ModuleBuilder::new()
|
||||
ModuleBuilder::new()
|
||||
}
|
||||
|
||||
/// Start builder to extend existing module
|
||||
pub fn from_module(module: elements::Module) -> ModuleBuilder {
|
||||
ModuleBuilder::new().with_module(module)
|
||||
ModuleBuilder::new().with_module(module)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::module;
|
||||
use super::module;
|
||||
|
||||
#[test]
|
||||
fn smoky() {
|
||||
let module = module().build();
|
||||
assert_eq!(module.sections().len(), 0);
|
||||
}
|
||||
#[test]
|
||||
fn smoky() {
|
||||
let module = module().build();
|
||||
assert_eq!(module.sections().len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn functions() {
|
||||
let module = module()
|
||||
.function()
|
||||
.signature().param().i32().build()
|
||||
.body().build()
|
||||
.build()
|
||||
.build();
|
||||
#[test]
|
||||
fn functions() {
|
||||
let module = module()
|
||||
.function()
|
||||
.signature().param().i32().build()
|
||||
.body().build()
|
||||
.build()
|
||||
.build();
|
||||
|
||||
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.code_section().expect("code section to exist").bodies().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.code_section().expect("code section to exist").bodies().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn export() {
|
||||
let module = module()
|
||||
.export().field("call").internal().func(0).build()
|
||||
.build();
|
||||
#[test]
|
||||
fn export() {
|
||||
let module = module()
|
||||
.export().field("call").internal().func(0).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]
|
||||
fn global() {
|
||||
let module = module()
|
||||
.global().value_type().i64().mutable().init_expr(::elements::Opcode::I64Const(5)).build()
|
||||
.build();
|
||||
#[test]
|
||||
fn global() {
|
||||
let module = module()
|
||||
.global().value_type().i64().mutable().init_expr(::elements::Opcode::I64Const(5)).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]
|
||||
fn data() {
|
||||
let module = module()
|
||||
.data()
|
||||
.offset(::elements::Opcode::I32Const(16))
|
||||
.value(vec![0u8, 15, 10, 5, 25])
|
||||
.build()
|
||||
.build();
|
||||
#[test]
|
||||
fn data() {
|
||||
let module = module()
|
||||
.data()
|
||||
.offset(::elements::Opcode::I32Const(16))
|
||||
.value(vec![0u8, 15, 10, 5, 25])
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
@ -4,81 +4,81 @@ use super::invoke::{Invoke, Identity};
|
||||
/// Table definition
|
||||
#[derive(Debug)]
|
||||
pub struct TableDefinition {
|
||||
/// Minimum length
|
||||
pub min: u32,
|
||||
/// Maximum length, if any
|
||||
pub max: Option<u32>,
|
||||
/// Element segments, if any
|
||||
pub elements: Vec<TableEntryDefinition>,
|
||||
/// Minimum length
|
||||
pub min: u32,
|
||||
/// Maximum length, if any
|
||||
pub max: Option<u32>,
|
||||
/// Element segments, if any
|
||||
pub elements: Vec<TableEntryDefinition>,
|
||||
}
|
||||
|
||||
/// Table elements entry definition
|
||||
#[derive(Debug)]
|
||||
pub struct TableEntryDefinition {
|
||||
/// Offset initialization expression
|
||||
pub offset: elements::InitExpr,
|
||||
/// Values of initialization
|
||||
pub values: Vec<u32>,
|
||||
/// Offset initialization expression
|
||||
pub offset: elements::InitExpr,
|
||||
/// Values of initialization
|
||||
pub values: Vec<u32>,
|
||||
}
|
||||
|
||||
/// Table builder
|
||||
pub struct TableBuilder<F=Identity> {
|
||||
callback: F,
|
||||
table: TableDefinition,
|
||||
callback: F,
|
||||
table: TableDefinition,
|
||||
}
|
||||
|
||||
impl TableBuilder {
|
||||
/// New table builder
|
||||
pub fn new() -> Self {
|
||||
TableBuilder::with_callback(Identity)
|
||||
}
|
||||
/// New table builder
|
||||
pub fn new() -> Self {
|
||||
TableBuilder::with_callback(Identity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> TableBuilder<F> where F: Invoke<TableDefinition> {
|
||||
/// New table builder with callback in chained context
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
TableBuilder {
|
||||
callback: callback,
|
||||
table: Default::default(),
|
||||
}
|
||||
}
|
||||
/// New table builder with callback in chained context
|
||||
pub fn with_callback(callback: F) -> Self {
|
||||
TableBuilder {
|
||||
callback: callback,
|
||||
table: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set/override minimum length
|
||||
pub fn with_min(mut self, min: u32) -> Self {
|
||||
self.table.min = min;
|
||||
self
|
||||
}
|
||||
/// Set/override minimum length
|
||||
pub fn with_min(mut self, min: u32) -> Self {
|
||||
self.table.min = min;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set/override maximum length
|
||||
pub fn with_max(mut self, max: Option<u32>) -> Self {
|
||||
self.table.max = max;
|
||||
self
|
||||
}
|
||||
/// Set/override maximum length
|
||||
pub fn with_max(mut self, max: Option<u32>) -> Self {
|
||||
self.table.max = max;
|
||||
self
|
||||
}
|
||||
|
||||
/// Generate initialization expression and element values on specified index
|
||||
pub fn with_element(mut self, index: u32, values: Vec<u32>) -> Self {
|
||||
self.table.elements.push(TableEntryDefinition {
|
||||
offset: elements::InitExpr::new(vec![
|
||||
elements::Opcode::I32Const(index as i32),
|
||||
elements::Opcode::End,
|
||||
]),
|
||||
values: values,
|
||||
});
|
||||
self
|
||||
}
|
||||
/// Generate initialization expression and element values on specified index
|
||||
pub fn with_element(mut self, index: u32, values: Vec<u32>) -> Self {
|
||||
self.table.elements.push(TableEntryDefinition {
|
||||
offset: elements::InitExpr::new(vec![
|
||||
elements::Opcode::I32Const(index as i32),
|
||||
elements::Opcode::End,
|
||||
]),
|
||||
values: values,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Finalize current builder spawning resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.table)
|
||||
}
|
||||
/// Finalize current builder spawning resulting struct
|
||||
pub fn build(self) -> F::Result {
|
||||
self.callback.invoke(self.table)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TableDefinition {
|
||||
fn default() -> Self {
|
||||
TableDefinition {
|
||||
min: 0,
|
||||
max: None,
|
||||
elements: Vec::new(),
|
||||
}
|
||||
}
|
||||
fn default() -> Self {
|
||||
TableDefinition {
|
||||
min: 0,
|
||||
max: None,
|
||||
elements: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,98 +4,98 @@ use super::{Deserialize, Serialize, Error, VarUint7, VarUint32};
|
||||
/// Internal reference of the exported entry.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Internal {
|
||||
/// Function reference.
|
||||
Function(u32),
|
||||
/// Table reference.
|
||||
Table(u32),
|
||||
/// Memory reference.
|
||||
Memory(u32),
|
||||
/// Global reference.
|
||||
Global(u32),
|
||||
/// Function reference.
|
||||
Function(u32),
|
||||
/// Table reference.
|
||||
Table(u32),
|
||||
/// Memory reference.
|
||||
Memory(u32),
|
||||
/// Global reference.
|
||||
Global(u32),
|
||||
}
|
||||
|
||||
impl Deserialize for Internal {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let kind = VarUint7::deserialize(reader)?;
|
||||
match kind.into() {
|
||||
0x00 => Ok(Internal::Function(VarUint32::deserialize(reader)?.into())),
|
||||
0x01 => Ok(Internal::Table(VarUint32::deserialize(reader)?.into())),
|
||||
0x02 => Ok(Internal::Memory(VarUint32::deserialize(reader)?.into())),
|
||||
0x03 => Ok(Internal::Global(VarUint32::deserialize(reader)?.into())),
|
||||
_ => Err(Error::UnknownInternalKind(kind.into())),
|
||||
}
|
||||
}
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let kind = VarUint7::deserialize(reader)?;
|
||||
match kind.into() {
|
||||
0x00 => Ok(Internal::Function(VarUint32::deserialize(reader)?.into())),
|
||||
0x01 => Ok(Internal::Table(VarUint32::deserialize(reader)?.into())),
|
||||
0x02 => Ok(Internal::Memory(VarUint32::deserialize(reader)?.into())),
|
||||
0x03 => Ok(Internal::Global(VarUint32::deserialize(reader)?.into())),
|
||||
_ => Err(Error::UnknownInternalKind(kind.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Internal {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let (bt, arg) = match self {
|
||||
Internal::Function(arg) => (0x00, arg),
|
||||
Internal::Table(arg) => (0x01, arg),
|
||||
Internal::Memory(arg) => (0x02, arg),
|
||||
Internal::Global(arg) => (0x03, arg),
|
||||
};
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let (bt, arg) = match self {
|
||||
Internal::Function(arg) => (0x00, arg),
|
||||
Internal::Table(arg) => (0x01, arg),
|
||||
Internal::Memory(arg) => (0x02, arg),
|
||||
Internal::Global(arg) => (0x03, arg),
|
||||
};
|
||||
|
||||
VarUint7::from(bt).serialize(writer)?;
|
||||
VarUint32::from(arg).serialize(writer)?;
|
||||
VarUint7::from(bt).serialize(writer)?;
|
||||
VarUint32::from(arg).serialize(writer)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Export entry.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExportEntry {
|
||||
field_str: String,
|
||||
internal: Internal,
|
||||
field_str: String,
|
||||
internal: Internal,
|
||||
}
|
||||
|
||||
impl ExportEntry {
|
||||
/// New export entry
|
||||
pub fn new(field: String, internal: Internal) -> Self {
|
||||
ExportEntry {
|
||||
field_str: field,
|
||||
internal: internal
|
||||
}
|
||||
}
|
||||
/// New export entry
|
||||
pub fn new(field: String, internal: Internal) -> Self {
|
||||
ExportEntry {
|
||||
field_str: field,
|
||||
internal: internal
|
||||
}
|
||||
}
|
||||
|
||||
/// Public name
|
||||
pub fn field(&self) -> &str { &self.field_str }
|
||||
/// Public name
|
||||
pub fn field(&self) -> &str { &self.field_str }
|
||||
|
||||
/// Public name (mutable)
|
||||
pub fn field_mut(&mut self) -> &mut String { &mut self.field_str }
|
||||
/// Public name (mutable)
|
||||
pub fn field_mut(&mut self) -> &mut String { &mut self.field_str }
|
||||
|
||||
/// Internal reference of the export entry.
|
||||
pub fn internal(&self) -> &Internal { &self.internal }
|
||||
/// Internal reference of the export entry.
|
||||
pub fn internal(&self) -> &Internal { &self.internal }
|
||||
|
||||
/// Internal reference of the export entry (mutable).
|
||||
pub fn internal_mut(&mut self) -> &mut Internal { &mut self.internal }
|
||||
/// Internal reference of the export entry (mutable).
|
||||
pub fn internal_mut(&mut self) -> &mut Internal { &mut self.internal }
|
||||
}
|
||||
|
||||
impl Deserialize for ExportEntry {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let field_str = String::deserialize(reader)?;
|
||||
let internal = Internal::deserialize(reader)?;
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let field_str = String::deserialize(reader)?;
|
||||
let internal = Internal::deserialize(reader)?;
|
||||
|
||||
Ok(ExportEntry {
|
||||
field_str: field_str,
|
||||
internal: internal,
|
||||
})
|
||||
}
|
||||
Ok(ExportEntry {
|
||||
field_str: field_str,
|
||||
internal: internal,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ExportEntry {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.field_str.serialize(writer)?;
|
||||
self.internal.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.field_str.serialize(writer)?;
|
||||
self.internal.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::io;
|
||||
use super::{
|
||||
Deserialize, Error, ValueType, VarUint32, CountedList, Opcodes,
|
||||
Serialize, CountedWriter, CountedListWriter,
|
||||
Deserialize, Error, ValueType, VarUint32, CountedList, Opcodes,
|
||||
Serialize, CountedWriter, CountedListWriter,
|
||||
};
|
||||
|
||||
/// Function signature (type reference)
|
||||
@ -9,122 +9,122 @@ use super::{
|
||||
pub struct Func(u32);
|
||||
|
||||
impl Func {
|
||||
/// New function signature
|
||||
pub fn new(type_ref: u32) -> Self { Func(type_ref) }
|
||||
/// New function signature
|
||||
pub fn new(type_ref: u32) -> Self { Func(type_ref) }
|
||||
|
||||
/// Function signature type reference.
|
||||
pub fn type_ref(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
/// Function signature type reference.
|
||||
pub fn type_ref(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Function signature type reference (mutable).
|
||||
pub fn type_ref_mut(&mut self) -> &mut u32 {
|
||||
&mut self.0
|
||||
}
|
||||
/// Function signature type reference (mutable).
|
||||
pub fn type_ref_mut(&mut self) -> &mut u32 {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Local definition inside the function body.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Local {
|
||||
count: u32,
|
||||
value_type: ValueType,
|
||||
count: u32,
|
||||
value_type: ValueType,
|
||||
}
|
||||
|
||||
impl Local {
|
||||
/// New local with `count` and `value_type`.
|
||||
pub fn new(count: u32, value_type: ValueType) -> Self {
|
||||
Local { count: count, value_type: value_type }
|
||||
}
|
||||
/// New local with `count` and `value_type`.
|
||||
pub fn new(count: u32, value_type: ValueType) -> Self {
|
||||
Local { count: count, value_type: value_type }
|
||||
}
|
||||
|
||||
/// Number of locals with the shared type.
|
||||
pub fn count(&self) -> u32 { self.count }
|
||||
/// Number of locals with the shared type.
|
||||
pub fn count(&self) -> u32 { self.count }
|
||||
|
||||
/// Type of the locals.
|
||||
pub fn value_type(&self) -> ValueType { self.value_type }
|
||||
/// Type of the locals.
|
||||
pub fn value_type(&self) -> ValueType { self.value_type }
|
||||
}
|
||||
|
||||
impl Deserialize for Local {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let count = VarUint32::deserialize(reader)?;
|
||||
let value_type = ValueType::deserialize(reader)?;
|
||||
Ok(Local { count: count.into(), value_type: value_type })
|
||||
}
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let count = VarUint32::deserialize(reader)?;
|
||||
let value_type = ValueType::deserialize(reader)?;
|
||||
Ok(Local { count: count.into(), value_type: value_type })
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Local {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
VarUint32::from(self.count).serialize(writer)?;
|
||||
self.value_type.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
VarUint32::from(self.count).serialize(writer)?;
|
||||
self.value_type.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Function body definition.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FuncBody {
|
||||
locals: Vec<Local>,
|
||||
opcodes: Opcodes,
|
||||
locals: Vec<Local>,
|
||||
opcodes: Opcodes,
|
||||
}
|
||||
|
||||
impl FuncBody {
|
||||
/// New function body with given `locals` and `opcodes`
|
||||
pub fn new(locals: Vec<Local>, opcodes: Opcodes) -> Self {
|
||||
FuncBody { locals: locals, opcodes: opcodes }
|
||||
}
|
||||
/// New function body with given `locals` and `opcodes`
|
||||
pub fn new(locals: Vec<Local>, opcodes: Opcodes) -> Self {
|
||||
FuncBody { locals: locals, opcodes: opcodes }
|
||||
}
|
||||
|
||||
/// List of individual opcodes
|
||||
pub fn empty() -> Self {
|
||||
FuncBody { locals: Vec::new(), opcodes: Opcodes::empty() }
|
||||
}
|
||||
/// List of individual opcodes
|
||||
pub fn empty() -> Self {
|
||||
FuncBody { locals: Vec::new(), opcodes: Opcodes::empty() }
|
||||
}
|
||||
|
||||
/// Locals declared in function body.
|
||||
pub fn locals(&self) -> &[Local] { &self.locals }
|
||||
/// Locals declared in function body.
|
||||
pub fn locals(&self) -> &[Local] { &self.locals }
|
||||
|
||||
/// Opcode sequence of the function body. Minimal opcode sequence
|
||||
/// is just `&[Opcode::End]`
|
||||
pub fn code(&self) -> &Opcodes { &self.opcodes }
|
||||
/// Opcode sequence of the function body. Minimal opcode sequence
|
||||
/// is just `&[Opcode::End]`
|
||||
pub fn code(&self) -> &Opcodes { &self.opcodes }
|
||||
|
||||
/// Locals declared in function body (mutable).
|
||||
pub fn locals_mut(&mut self) -> &mut Vec<Local> { &mut self.locals }
|
||||
/// Locals declared in function body (mutable).
|
||||
pub fn locals_mut(&mut self) -> &mut Vec<Local> { &mut self.locals }
|
||||
|
||||
/// Opcode sequence of the function body (mutable).
|
||||
pub fn code_mut(&mut self) -> &mut Opcodes { &mut self.opcodes }
|
||||
/// Opcode sequence of the function body (mutable).
|
||||
pub fn code_mut(&mut self) -> &mut Opcodes { &mut self.opcodes }
|
||||
}
|
||||
|
||||
impl Deserialize for FuncBody {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
// todo: maybe use reader.take(section_length)
|
||||
let _body_size = VarUint32::deserialize(reader)?;
|
||||
let locals: Vec<Local> = CountedList::deserialize(reader)?.into_inner();
|
||||
let opcodes = Opcodes::deserialize(reader)?;
|
||||
Ok(FuncBody { locals: locals, opcodes: opcodes })
|
||||
}
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
// todo: maybe use reader.take(section_length)
|
||||
let _body_size = VarUint32::deserialize(reader)?;
|
||||
let locals: Vec<Local> = CountedList::deserialize(reader)?.into_inner();
|
||||
let opcodes = Opcodes::deserialize(reader)?;
|
||||
Ok(FuncBody { locals: locals, opcodes: opcodes })
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for FuncBody {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let mut counted_writer = CountedWriter::new(writer);
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let mut counted_writer = CountedWriter::new(writer);
|
||||
|
||||
let data = self.locals;
|
||||
let counted_list = CountedListWriter::<Local, _>(
|
||||
data.len(),
|
||||
data.into_iter().map(Into::into),
|
||||
);
|
||||
counted_list.serialize(&mut counted_writer)?;
|
||||
let data = self.locals;
|
||||
let counted_list = CountedListWriter::<Local, _>(
|
||||
data.len(),
|
||||
data.into_iter().map(Into::into),
|
||||
);
|
||||
counted_list.serialize(&mut counted_writer)?;
|
||||
|
||||
let code = self.opcodes;
|
||||
code.serialize(&mut counted_writer)?;
|
||||
let code = self.opcodes;
|
||||
code.serialize(&mut counted_writer)?;
|
||||
|
||||
counted_writer.done()?;
|
||||
counted_writer.done()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -4,47 +4,47 @@ use super::{Deserialize, Serialize, Error, GlobalType, InitExpr};
|
||||
/// Global entry in the module.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GlobalEntry {
|
||||
global_type: GlobalType,
|
||||
init_expr: InitExpr,
|
||||
global_type: GlobalType,
|
||||
init_expr: InitExpr,
|
||||
}
|
||||
|
||||
impl GlobalEntry {
|
||||
/// New global entry
|
||||
pub fn new(global_type: GlobalType, init_expr: InitExpr) -> Self {
|
||||
GlobalEntry {
|
||||
global_type: global_type,
|
||||
init_expr: init_expr,
|
||||
}
|
||||
}
|
||||
/// Global type.
|
||||
pub fn global_type(&self) -> &GlobalType { &self.global_type }
|
||||
/// Initialization expression (opcodes) for global.
|
||||
pub fn init_expr(&self) -> &InitExpr { &self.init_expr }
|
||||
/// Global type (mutable)
|
||||
pub fn global_type_mut(&mut self) -> &mut GlobalType { &mut self.global_type }
|
||||
/// Initialization expression (opcodes) for global (mutable)
|
||||
pub fn init_expr_mut(&mut self) -> &mut InitExpr { &mut self.init_expr }
|
||||
/// New global entry
|
||||
pub fn new(global_type: GlobalType, init_expr: InitExpr) -> Self {
|
||||
GlobalEntry {
|
||||
global_type: global_type,
|
||||
init_expr: init_expr,
|
||||
}
|
||||
}
|
||||
/// Global type.
|
||||
pub fn global_type(&self) -> &GlobalType { &self.global_type }
|
||||
/// Initialization expression (opcodes) for global.
|
||||
pub fn init_expr(&self) -> &InitExpr { &self.init_expr }
|
||||
/// Global type (mutable)
|
||||
pub fn global_type_mut(&mut self) -> &mut GlobalType { &mut self.global_type }
|
||||
/// Initialization expression (opcodes) for global (mutable)
|
||||
pub fn init_expr_mut(&mut self) -> &mut InitExpr { &mut self.init_expr }
|
||||
}
|
||||
|
||||
impl Deserialize for GlobalEntry {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let global_type = GlobalType::deserialize(reader)?;
|
||||
let init_expr = InitExpr::deserialize(reader)?;
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let global_type = GlobalType::deserialize(reader)?;
|
||||
let init_expr = InitExpr::deserialize(reader)?;
|
||||
|
||||
Ok(GlobalEntry {
|
||||
global_type: global_type,
|
||||
init_expr: init_expr,
|
||||
})
|
||||
}
|
||||
Ok(GlobalEntry {
|
||||
global_type: global_type,
|
||||
init_expr: init_expr,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for GlobalEntry {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.global_type.serialize(writer)?;
|
||||
self.init_expr.serialize(writer)
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.global_type.serialize(writer)?;
|
||||
self.init_expr.serialize(writer)
|
||||
}
|
||||
}
|
||||
|
@ -1,152 +1,152 @@
|
||||
use std::io;
|
||||
use super::{
|
||||
Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1,
|
||||
ValueType, TableElementType
|
||||
Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1,
|
||||
ValueType, TableElementType
|
||||
};
|
||||
|
||||
/// Global definition struct
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct GlobalType {
|
||||
content_type: ValueType,
|
||||
is_mutable: bool,
|
||||
content_type: ValueType,
|
||||
is_mutable: bool,
|
||||
}
|
||||
|
||||
impl GlobalType {
|
||||
/// New global type
|
||||
pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
|
||||
GlobalType {
|
||||
content_type: content_type,
|
||||
is_mutable: is_mutable,
|
||||
}
|
||||
}
|
||||
/// New global type
|
||||
pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
|
||||
GlobalType {
|
||||
content_type: content_type,
|
||||
is_mutable: is_mutable,
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of the global entry
|
||||
pub fn content_type(&self) -> ValueType { self.content_type }
|
||||
/// Type of the global entry
|
||||
pub fn content_type(&self) -> ValueType { self.content_type }
|
||||
|
||||
/// Is global entry is declared as mutable
|
||||
pub fn is_mutable(&self) -> bool { self.is_mutable }
|
||||
/// Is global entry is declared as mutable
|
||||
pub fn is_mutable(&self) -> bool { self.is_mutable }
|
||||
}
|
||||
|
||||
impl Deserialize for GlobalType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let content_type = ValueType::deserialize(reader)?;
|
||||
let is_mutable = VarUint1::deserialize(reader)?;
|
||||
Ok(GlobalType {
|
||||
content_type: content_type,
|
||||
is_mutable: is_mutable.into(),
|
||||
})
|
||||
}
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let content_type = ValueType::deserialize(reader)?;
|
||||
let is_mutable = VarUint1::deserialize(reader)?;
|
||||
Ok(GlobalType {
|
||||
content_type: content_type,
|
||||
is_mutable: is_mutable.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for GlobalType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.content_type.serialize(writer)?;
|
||||
VarUint1::from(self.is_mutable).serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.content_type.serialize(writer)?;
|
||||
VarUint1::from(self.is_mutable).serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Table entry
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TableType {
|
||||
elem_type: TableElementType,
|
||||
limits: ResizableLimits,
|
||||
elem_type: TableElementType,
|
||||
limits: ResizableLimits,
|
||||
}
|
||||
|
||||
impl TableType {
|
||||
/// New table definition
|
||||
pub fn new(min: u32, max: Option<u32>) -> Self {
|
||||
TableType {
|
||||
elem_type: TableElementType::AnyFunc,
|
||||
limits: ResizableLimits::new(min, max),
|
||||
}
|
||||
}
|
||||
/// New table definition
|
||||
pub fn new(min: u32, max: Option<u32>) -> Self {
|
||||
TableType {
|
||||
elem_type: TableElementType::AnyFunc,
|
||||
limits: ResizableLimits::new(min, max),
|
||||
}
|
||||
}
|
||||
|
||||
/// Table memory specification
|
||||
pub fn limits(&self) -> &ResizableLimits { &self.limits }
|
||||
/// Table memory specification
|
||||
pub fn limits(&self) -> &ResizableLimits { &self.limits }
|
||||
|
||||
/// Table element type
|
||||
pub fn elem_type(&self) -> TableElementType { self.elem_type }
|
||||
/// Table element type
|
||||
pub fn elem_type(&self) -> TableElementType { self.elem_type }
|
||||
}
|
||||
|
||||
impl Deserialize for TableType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let elem_type = TableElementType::deserialize(reader)?;
|
||||
let limits = ResizableLimits::deserialize(reader)?;
|
||||
Ok(TableType {
|
||||
elem_type: elem_type,
|
||||
limits: limits,
|
||||
})
|
||||
}
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let elem_type = TableElementType::deserialize(reader)?;
|
||||
let limits = ResizableLimits::deserialize(reader)?;
|
||||
Ok(TableType {
|
||||
elem_type: elem_type,
|
||||
limits: limits,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TableType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.elem_type.serialize(writer)?;
|
||||
self.limits.serialize(writer)
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.elem_type.serialize(writer)?;
|
||||
self.limits.serialize(writer)
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory limits
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ResizableLimits {
|
||||
initial: u32,
|
||||
maximum: Option<u32>,
|
||||
initial: u32,
|
||||
maximum: Option<u32>,
|
||||
}
|
||||
|
||||
impl ResizableLimits {
|
||||
/// New memory limits definition
|
||||
pub fn new(min: u32, max: Option<u32>) -> Self {
|
||||
ResizableLimits {
|
||||
initial: min,
|
||||
maximum: max,
|
||||
}
|
||||
}
|
||||
/// Initial size
|
||||
pub fn initial(&self) -> u32 { self.initial }
|
||||
/// Maximum size
|
||||
pub fn maximum(&self) -> Option<u32> { self.maximum }
|
||||
/// New memory limits definition
|
||||
pub fn new(min: u32, max: Option<u32>) -> Self {
|
||||
ResizableLimits {
|
||||
initial: min,
|
||||
maximum: max,
|
||||
}
|
||||
}
|
||||
/// Initial size
|
||||
pub fn initial(&self) -> u32 { self.initial }
|
||||
/// Maximum size
|
||||
pub fn maximum(&self) -> Option<u32> { self.maximum }
|
||||
}
|
||||
|
||||
impl Deserialize for ResizableLimits {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let has_max = VarUint1::deserialize(reader)?;
|
||||
let initial = VarUint32::deserialize(reader)?;
|
||||
let maximum = if has_max.into() {
|
||||
Some(VarUint32::deserialize(reader)?.into())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let has_max = VarUint1::deserialize(reader)?;
|
||||
let initial = VarUint32::deserialize(reader)?;
|
||||
let maximum = if has_max.into() {
|
||||
Some(VarUint32::deserialize(reader)?.into())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(ResizableLimits {
|
||||
initial: initial.into(),
|
||||
maximum: maximum,
|
||||
})
|
||||
}
|
||||
Ok(ResizableLimits {
|
||||
initial: initial.into(),
|
||||
maximum: maximum,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ResizableLimits {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let max = self.maximum;
|
||||
VarUint1::from(max.is_some()).serialize(writer)?;
|
||||
VarUint32::from(self.initial).serialize(writer)?;
|
||||
if let Some(val) = max {
|
||||
VarUint32::from(val).serialize(writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let max = self.maximum;
|
||||
VarUint1::from(max.is_some()).serialize(writer)?;
|
||||
VarUint32::from(self.initial).serialize(writer)?;
|
||||
if let Some(val) = max {
|
||||
VarUint32::from(val).serialize(writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Memory entry.
|
||||
@ -154,152 +154,152 @@ impl Serialize for ResizableLimits {
|
||||
pub struct MemoryType(ResizableLimits);
|
||||
|
||||
impl MemoryType {
|
||||
/// New memory definition
|
||||
pub fn new(min: u32, max: Option<u32>) -> Self {
|
||||
MemoryType(ResizableLimits::new(min, max))
|
||||
}
|
||||
/// Limits of the memory entry.
|
||||
pub fn limits(&self) -> &ResizableLimits {
|
||||
&self.0
|
||||
}
|
||||
/// New memory definition
|
||||
pub fn new(min: u32, max: Option<u32>) -> Self {
|
||||
MemoryType(ResizableLimits::new(min, max))
|
||||
}
|
||||
/// Limits of the memory entry.
|
||||
pub fn limits(&self) -> &ResizableLimits {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize for MemoryType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
Ok(MemoryType(ResizableLimits::deserialize(reader)?))
|
||||
}
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
Ok(MemoryType(ResizableLimits::deserialize(reader)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for MemoryType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.0.serialize(writer)
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.0.serialize(writer)
|
||||
}
|
||||
}
|
||||
|
||||
/// External to local binding.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum External {
|
||||
/// Binds to function with index.
|
||||
Function(u32),
|
||||
/// Describes local table definition to be imported as.
|
||||
Table(TableType),
|
||||
/// Describes local memory definition to be imported as.
|
||||
Memory(MemoryType),
|
||||
/// Describes local global entry to be imported as.
|
||||
Global(GlobalType),
|
||||
/// Binds to function with index.
|
||||
Function(u32),
|
||||
/// Describes local table definition to be imported as.
|
||||
Table(TableType),
|
||||
/// Describes local memory definition to be imported as.
|
||||
Memory(MemoryType),
|
||||
/// Describes local global entry to be imported as.
|
||||
Global(GlobalType),
|
||||
}
|
||||
|
||||
impl Deserialize for External {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let kind = VarUint7::deserialize(reader)?;
|
||||
match kind.into() {
|
||||
0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
|
||||
0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
|
||||
0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
|
||||
0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
|
||||
_ => Err(Error::UnknownExternalKind(kind.into())),
|
||||
}
|
||||
}
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let kind = VarUint7::deserialize(reader)?;
|
||||
match kind.into() {
|
||||
0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
|
||||
0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
|
||||
0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
|
||||
0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
|
||||
_ => Err(Error::UnknownExternalKind(kind.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for External {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
use self::External::*;
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
use self::External::*;
|
||||
|
||||
match self {
|
||||
Function(index) => {
|
||||
VarUint7::from(0x00).serialize(writer)?;
|
||||
VarUint32::from(index).serialize(writer)?;
|
||||
},
|
||||
Table(tt) => {
|
||||
VarInt7::from(0x01).serialize(writer)?;
|
||||
tt.serialize(writer)?;
|
||||
},
|
||||
Memory(mt) => {
|
||||
VarInt7::from(0x02).serialize(writer)?;
|
||||
mt.serialize(writer)?;
|
||||
},
|
||||
Global(gt) => {
|
||||
VarInt7::from(0x03).serialize(writer)?;
|
||||
gt.serialize(writer)?;
|
||||
},
|
||||
}
|
||||
match self {
|
||||
Function(index) => {
|
||||
VarUint7::from(0x00).serialize(writer)?;
|
||||
VarUint32::from(index).serialize(writer)?;
|
||||
},
|
||||
Table(tt) => {
|
||||
VarInt7::from(0x01).serialize(writer)?;
|
||||
tt.serialize(writer)?;
|
||||
},
|
||||
Memory(mt) => {
|
||||
VarInt7::from(0x02).serialize(writer)?;
|
||||
mt.serialize(writer)?;
|
||||
},
|
||||
Global(gt) => {
|
||||
VarInt7::from(0x03).serialize(writer)?;
|
||||
gt.serialize(writer)?;
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Import entry.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ImportEntry {
|
||||
module_str: String,
|
||||
field_str: String,
|
||||
external: External,
|
||||
module_str: String,
|
||||
field_str: String,
|
||||
external: External,
|
||||
}
|
||||
|
||||
impl ImportEntry {
|
||||
/// New import entry.
|
||||
pub fn new(module_str: String, field_str: String, external: External) -> Self {
|
||||
ImportEntry {
|
||||
module_str: module_str,
|
||||
field_str: field_str,
|
||||
external: external,
|
||||
}
|
||||
}
|
||||
/// New import entry.
|
||||
pub fn new(module_str: String, field_str: String, external: External) -> Self {
|
||||
ImportEntry {
|
||||
module_str: module_str,
|
||||
field_str: field_str,
|
||||
external: external,
|
||||
}
|
||||
}
|
||||
|
||||
/// Module reference of the import entry.
|
||||
pub fn module(&self) -> &str { &self.module_str }
|
||||
/// Module reference of the import entry.
|
||||
pub fn module(&self) -> &str { &self.module_str }
|
||||
|
||||
/// Module reference of the import entry (mutable).
|
||||
pub fn module_mut(&mut self) -> &mut String {
|
||||
&mut self.module_str
|
||||
}
|
||||
/// Module reference of the import entry (mutable).
|
||||
pub fn module_mut(&mut self) -> &mut String {
|
||||
&mut self.module_str
|
||||
}
|
||||
|
||||
/// Field reference of the import entry.
|
||||
pub fn field(&self) -> &str { &self.field_str }
|
||||
/// Field reference of the import entry.
|
||||
pub fn field(&self) -> &str { &self.field_str }
|
||||
|
||||
/// Field reference of the import entry (mutable)
|
||||
pub fn field_mut(&mut self) -> &mut String {
|
||||
&mut self.field_str
|
||||
}
|
||||
/// Field reference of the import entry (mutable)
|
||||
pub fn field_mut(&mut self) -> &mut String {
|
||||
&mut self.field_str
|
||||
}
|
||||
|
||||
/// Local binidng of the import entry.
|
||||
pub fn external(&self) -> &External { &self.external }
|
||||
/// Local binidng of the import entry.
|
||||
pub fn external(&self) -> &External { &self.external }
|
||||
|
||||
/// Local binidng of the import entry (mutable)
|
||||
pub fn external_mut(&mut self) -> &mut External { &mut self.external }
|
||||
/// Local binidng of the import entry (mutable)
|
||||
pub fn external_mut(&mut self) -> &mut External { &mut self.external }
|
||||
}
|
||||
|
||||
impl Deserialize for ImportEntry {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let module_str = String::deserialize(reader)?;
|
||||
let field_str = String::deserialize(reader)?;
|
||||
let external = External::deserialize(reader)?;
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let module_str = String::deserialize(reader)?;
|
||||
let field_str = String::deserialize(reader)?;
|
||||
let external = External::deserialize(reader)?;
|
||||
|
||||
Ok(ImportEntry {
|
||||
module_str: module_str,
|
||||
field_str: field_str,
|
||||
external: external,
|
||||
})
|
||||
}
|
||||
Ok(ImportEntry {
|
||||
module_str: module_str,
|
||||
field_str: field_str,
|
||||
external: external,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ImportEntry {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.module_str.serialize(writer)?;
|
||||
self.field_str.serialize(writer)?;
|
||||
self.external.serialize(writer)
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
self.module_str.serialize(writer)?;
|
||||
self.field_str.serialize(writer)?;
|
||||
self.external.serialize(writer)
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,16 +19,16 @@ mod name_section;
|
||||
|
||||
pub use self::module::{Module, peek_size, ImportCountType};
|
||||
pub use self::section::{
|
||||
Section, FunctionSection, CodeSection, MemorySection, DataSection,
|
||||
ImportSection, ExportSection, GlobalSection, TypeSection, ElementSection,
|
||||
TableSection, CustomSection,
|
||||
Section, FunctionSection, CodeSection, MemorySection, DataSection,
|
||||
ImportSection, ExportSection, GlobalSection, TypeSection, ElementSection,
|
||||
TableSection, CustomSection,
|
||||
};
|
||||
pub use self::import_entry::{ImportEntry, ResizableLimits, MemoryType, TableType, GlobalType, External};
|
||||
pub use self::export_entry::{ExportEntry, Internal};
|
||||
pub use self::global_entry::GlobalEntry;
|
||||
pub use self::primitives::{
|
||||
VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64,
|
||||
Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter,
|
||||
VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64,
|
||||
Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter,
|
||||
};
|
||||
pub use self::types::{Type, ValueType, BlockType, FunctionType, TableElementType};
|
||||
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::index_map::IndexMap;
|
||||
pub use self::name_section::{
|
||||
NameMap, NameSection, ModuleNameSection, FunctionNameSection,
|
||||
LocalNameSection,
|
||||
NameMap, NameSection, ModuleNameSection, FunctionNameSection,
|
||||
LocalNameSection,
|
||||
};
|
||||
|
||||
/// Deserialization from serial i/o
|
||||
pub trait Deserialize : Sized {
|
||||
/// Serialization error produced by deserialization routine.
|
||||
type Error;
|
||||
/// Deserialize type from serial i/o
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
|
||||
/// Serialization error produced by deserialization routine.
|
||||
type Error;
|
||||
/// Deserialize type from serial i/o
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
|
||||
}
|
||||
|
||||
/// Serialization to serial i/o
|
||||
pub trait Serialize {
|
||||
/// Serialization error produced by serialization routine.
|
||||
type Error;
|
||||
/// Serialize type to serial i/o
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
|
||||
/// Serialization error produced by serialization routine.
|
||||
type Error;
|
||||
/// Serialize type to serial i/o
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// Deserialization/serialization error
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Error {
|
||||
/// Unexpected end of input
|
||||
UnexpectedEof,
|
||||
/// Invalid magic
|
||||
InvalidMagic,
|
||||
/// Unsupported version
|
||||
UnsupportedVersion(u32),
|
||||
/// Inconsistence between declared and actual length
|
||||
InconsistentLength {
|
||||
/// Expected length of the definition
|
||||
expected: usize,
|
||||
/// Actual length of the definition
|
||||
actual: usize
|
||||
},
|
||||
/// Other static error
|
||||
Other(&'static str),
|
||||
/// Other allocated error
|
||||
HeapOther(String),
|
||||
/// Invalid/unknown value type declaration
|
||||
UnknownValueType(i8),
|
||||
/// Invalid/unknown table element type declaration
|
||||
UnknownTableElementType(i8),
|
||||
/// Non-utf8 string
|
||||
NonUtf8String,
|
||||
/// Unknown external kind code
|
||||
UnknownExternalKind(u8),
|
||||
/// Unknown internal kind code
|
||||
UnknownInternalKind(u8),
|
||||
/// Unknown opcode encountered
|
||||
UnknownOpcode(u8),
|
||||
/// Invalid VarUint1 value
|
||||
InvalidVarUint1(u8),
|
||||
/// Invalid VarInt32 value
|
||||
InvalidVarInt32,
|
||||
/// Invalid VarInt64 value
|
||||
InvalidVarInt64,
|
||||
/// Unexpected end of input
|
||||
UnexpectedEof,
|
||||
/// Invalid magic
|
||||
InvalidMagic,
|
||||
/// Unsupported version
|
||||
UnsupportedVersion(u32),
|
||||
/// Inconsistence between declared and actual length
|
||||
InconsistentLength {
|
||||
/// Expected length of the definition
|
||||
expected: usize,
|
||||
/// Actual length of the definition
|
||||
actual: usize
|
||||
},
|
||||
/// Other static error
|
||||
Other(&'static str),
|
||||
/// Other allocated error
|
||||
HeapOther(String),
|
||||
/// Invalid/unknown value type declaration
|
||||
UnknownValueType(i8),
|
||||
/// Invalid/unknown table element type declaration
|
||||
UnknownTableElementType(i8),
|
||||
/// Non-utf8 string
|
||||
NonUtf8String,
|
||||
/// Unknown external kind code
|
||||
UnknownExternalKind(u8),
|
||||
/// Unknown internal kind code
|
||||
UnknownInternalKind(u8),
|
||||
/// Unknown opcode encountered
|
||||
UnknownOpcode(u8),
|
||||
/// Invalid VarUint1 value
|
||||
InvalidVarUint1(u8),
|
||||
/// Invalid VarInt32 value
|
||||
InvalidVarInt32,
|
||||
/// Invalid VarInt64 value
|
||||
InvalidVarInt64,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::UnexpectedEof => write!(f, "Unexpected end of input"),
|
||||
Error::InvalidMagic => write!(f, "Invalid magic number at start of file"),
|
||||
Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v),
|
||||
Error::InconsistentLength { expected, actual } => {
|
||||
write!(f, "Expected length {}, found {}", expected, actual)
|
||||
}
|
||||
Error::Other(msg) => write!(f, "{}", msg),
|
||||
Error::HeapOther(ref msg) => write!(f, "{}", msg),
|
||||
Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty),
|
||||
Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty),
|
||||
Error::NonUtf8String => write!(f, "Non-UTF-8 string"),
|
||||
Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind),
|
||||
Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind),
|
||||
Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode),
|
||||
Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val),
|
||||
Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"),
|
||||
Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"),
|
||||
}
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::UnexpectedEof => write!(f, "Unexpected end of input"),
|
||||
Error::InvalidMagic => write!(f, "Invalid magic number at start of file"),
|
||||
Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v),
|
||||
Error::InconsistentLength { expected, actual } => {
|
||||
write!(f, "Expected length {}, found {}", expected, actual)
|
||||
}
|
||||
Error::Other(msg) => write!(f, "{}", msg),
|
||||
Error::HeapOther(ref msg) => write!(f, "{}", msg),
|
||||
Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty),
|
||||
Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty),
|
||||
Error::NonUtf8String => write!(f, "Non-UTF-8 string"),
|
||||
Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind),
|
||||
Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind),
|
||||
Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode),
|
||||
Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val),
|
||||
Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"),
|
||||
Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::UnexpectedEof => "Unexpected end of input",
|
||||
Error::InvalidMagic => "Invalid magic number at start of file",
|
||||
Error::UnsupportedVersion(_) => "Unsupported wasm version",
|
||||
Error::InconsistentLength { .. } => "Inconsistent length",
|
||||
Error::Other(msg) => msg,
|
||||
Error::HeapOther(ref msg) => &msg[..],
|
||||
Error::UnknownValueType(_) => "Invalid or unknown value type",
|
||||
Error::UnknownTableElementType(_) => "Unknown table element type",
|
||||
Error::NonUtf8String => "Non-UTF-8 string",
|
||||
Error::UnknownExternalKind(_) => "Unknown external kind",
|
||||
Error::UnknownInternalKind(_) => "Unknown internal kind",
|
||||
Error::UnknownOpcode(_) => "Unknown opcode",
|
||||
Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer",
|
||||
Error::InvalidVarInt32 => "Not a signed 32-bit integer",
|
||||
Error::InvalidVarInt64 => "Not a signed 64-bit integer",
|
||||
}
|
||||
}
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::UnexpectedEof => "Unexpected end of input",
|
||||
Error::InvalidMagic => "Invalid magic number at start of file",
|
||||
Error::UnsupportedVersion(_) => "Unsupported wasm version",
|
||||
Error::InconsistentLength { .. } => "Inconsistent length",
|
||||
Error::Other(msg) => msg,
|
||||
Error::HeapOther(ref msg) => &msg[..],
|
||||
Error::UnknownValueType(_) => "Invalid or unknown value type",
|
||||
Error::UnknownTableElementType(_) => "Unknown table element type",
|
||||
Error::NonUtf8String => "Non-UTF-8 string",
|
||||
Error::UnknownExternalKind(_) => "Unknown external kind",
|
||||
Error::UnknownInternalKind(_) => "Unknown internal kind",
|
||||
Error::UnknownOpcode(_) => "Unknown opcode",
|
||||
Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer",
|
||||
Error::InvalidVarInt32 => "Not a signed 32-bit integer",
|
||||
Error::InvalidVarInt64 => "Not a signed 64-bit integer",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(err: io::Error) -> Self {
|
||||
Error::HeapOther(format!("I/O Error: {}", err))
|
||||
}
|
||||
fn from(err: io::Error) -> Self {
|
||||
Error::HeapOther(format!("I/O Error: {}", err))
|
||||
}
|
||||
}
|
||||
|
||||
/// Unparsed part of the module/section
|
||||
pub struct Unparsed(pub Vec<u8>);
|
||||
|
||||
impl Deserialize for Unparsed {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let len = VarUint32::deserialize(reader)?.into();
|
||||
let mut vec = vec![0u8; len];
|
||||
reader.read_exact(&mut vec[..])?;
|
||||
Ok(Unparsed(vec))
|
||||
}
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let len = VarUint32::deserialize(reader)?.into();
|
||||
let mut vec = vec![0u8; len];
|
||||
reader.read_exact(&mut vec[..])?;
|
||||
Ok(Unparsed(vec))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Unparsed> for Vec<u8> {
|
||||
fn from(u: Unparsed) -> Vec<u8> {
|
||||
u.0
|
||||
}
|
||||
fn from(u: Unparsed) -> Vec<u8> {
|
||||
u.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize module from file.
|
||||
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();
|
||||
::std::fs::File::open(p)?.read_to_end(&mut contents)?;
|
||||
let mut contents = Vec::new();
|
||||
::std::fs::File::open(p)?.read_to_end(&mut contents)?;
|
||||
|
||||
deserialize_buffer(&contents)
|
||||
deserialize_buffer(&contents)
|
||||
}
|
||||
|
||||
/// Deserialize deserializable type from buffer.
|
||||
pub fn deserialize_buffer<T: Deserialize>(contents: &[u8]) -> Result<T, T::Error> {
|
||||
let mut reader = io::Cursor::new(contents);
|
||||
T::deserialize(&mut reader)
|
||||
let mut reader = io::Cursor::new(contents);
|
||||
T::deserialize(&mut reader)
|
||||
}
|
||||
|
||||
/// Create buffer with serialized value.
|
||||
pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> {
|
||||
let mut buf = Vec::new();
|
||||
val.serialize(&mut buf)?;
|
||||
Ok(buf)
|
||||
let mut buf = Vec::new();
|
||||
val.serialize(&mut buf)?;
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
/// Serialize module to the file
|
||||
pub fn serialize_to_file<P: AsRef<::std::path::Path>>(p: P, module: Module) -> Result<(), Error>
|
||||
{
|
||||
let mut io = ::std::fs::File::create(p)?;
|
||||
module.serialize(&mut io)
|
||||
let mut io = ::std::fs::File::create(p)?;
|
||||
module.serialize(&mut io)
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ use byteorder::{LittleEndian, ByteOrder};
|
||||
|
||||
use super::{Deserialize, Serialize, Error, Uint32, External};
|
||||
use super::section::{
|
||||
Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection,
|
||||
GlobalSection, TableSection, ElementSection, DataSection, MemorySection
|
||||
Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection,
|
||||
GlobalSection, TableSection, ElementSection, DataSection, MemorySection
|
||||
};
|
||||
use super::name_section::NameSection;
|
||||
|
||||
@ -13,494 +13,494 @@ const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6d];
|
||||
/// WebAssembly module
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Module {
|
||||
magic: u32,
|
||||
version: u32,
|
||||
sections: Vec<Section>,
|
||||
magic: u32,
|
||||
version: u32,
|
||||
sections: Vec<Section>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
/// Type of the import entry to count
|
||||
pub enum ImportCountType {
|
||||
/// Count functions
|
||||
Function,
|
||||
/// Count globals
|
||||
Global,
|
||||
/// Count functions
|
||||
Function,
|
||||
/// Count globals
|
||||
Global,
|
||||
}
|
||||
|
||||
impl Default for Module {
|
||||
fn default() -> Self {
|
||||
Module {
|
||||
magic: LittleEndian::read_u32(&WASM_MAGIC_NUMBER),
|
||||
version: 1,
|
||||
sections: Vec::with_capacity(16),
|
||||
}
|
||||
}
|
||||
fn default() -> Self {
|
||||
Module {
|
||||
magic: LittleEndian::read_u32(&WASM_MAGIC_NUMBER),
|
||||
version: 1,
|
||||
sections: Vec::with_capacity(16),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Module {
|
||||
/// New module with sections
|
||||
pub fn new(sections: Vec<Section>) -> Self {
|
||||
Module {
|
||||
sections: sections, ..Default::default()
|
||||
}
|
||||
}
|
||||
/// New module with sections
|
||||
pub fn new(sections: Vec<Section>) -> Self {
|
||||
Module {
|
||||
sections: sections, ..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Destructure the module, yielding sections
|
||||
pub fn into_sections(self) -> Vec<Section> {
|
||||
self.sections
|
||||
}
|
||||
/// Destructure the module, yielding sections
|
||||
pub fn into_sections(self) -> Vec<Section> {
|
||||
self.sections
|
||||
}
|
||||
|
||||
/// Version of module.
|
||||
pub fn version(&self) -> u32 { self.version }
|
||||
/// Version of module.
|
||||
pub fn version(&self) -> u32 { self.version }
|
||||
|
||||
/// Sections list.
|
||||
/// Each known section is optional and may appear at most once.
|
||||
pub fn sections(&self) -> &[Section] {
|
||||
&self.sections
|
||||
}
|
||||
/// Sections list.
|
||||
/// Each known section is optional and may appear at most once.
|
||||
pub fn sections(&self) -> &[Section] {
|
||||
&self.sections
|
||||
}
|
||||
|
||||
/// Sections list (mutable)
|
||||
/// Each known section is optional and may appear at most once.
|
||||
pub fn sections_mut(&mut self) -> &mut Vec<Section> {
|
||||
&mut self.sections
|
||||
}
|
||||
/// Sections list (mutable)
|
||||
/// Each known section is optional and may appear at most once.
|
||||
pub fn sections_mut(&mut self) -> &mut Vec<Section> {
|
||||
&mut self.sections
|
||||
}
|
||||
|
||||
/// Code section, if any.
|
||||
pub fn code_section(&self) -> Option<&CodeSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Code(ref code_section) = section { return Some(code_section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Code section, if any.
|
||||
pub fn code_section(&self) -> Option<&CodeSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Code(ref code_section) = section { return Some(code_section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Types section, if any.
|
||||
pub fn type_section(&self) -> Option<&TypeSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Type(ref type_section) = section { return Some(type_section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Types section, if any.
|
||||
pub fn type_section(&self) -> Option<&TypeSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Type(ref type_section) = section { return Some(type_section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Imports section, if any.
|
||||
pub fn import_section(&self) -> Option<&ImportSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Import(ref import_section) = section { return Some(import_section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Imports section, if any.
|
||||
pub fn import_section(&self) -> Option<&ImportSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Import(ref import_section) = section { return Some(import_section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Globals section, if any.
|
||||
pub fn global_section(&self) -> Option<&GlobalSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Global(ref section) = section { return Some(section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Globals section, if any.
|
||||
pub fn global_section(&self) -> Option<&GlobalSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Global(ref section) = section { return Some(section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Exports section, if any.
|
||||
pub fn export_section(&self) -> Option<&ExportSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Export(ref export_section) = section { return Some(export_section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Exports section, if any.
|
||||
pub fn export_section(&self) -> Option<&ExportSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Export(ref export_section) = section { return Some(export_section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Table section, if any.
|
||||
pub fn table_section(&self) -> Option<&TableSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Table(ref section) = section { return Some(section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Table section, if any.
|
||||
pub fn table_section(&self) -> Option<&TableSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Table(ref section) = section { return Some(section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Data section, if any.
|
||||
pub fn data_section(&self) -> Option<&DataSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Data(ref section) = section { return Some(section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Data section, if any.
|
||||
pub fn data_section(&self) -> Option<&DataSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Data(ref section) = section { return Some(section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Element section, if any.
|
||||
pub fn elements_section(&self) -> Option<&ElementSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Element(ref section) = section { return Some(section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Element section, if any.
|
||||
pub fn elements_section(&self) -> Option<&ElementSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Element(ref section) = section { return Some(section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Memory section, if any.
|
||||
pub fn memory_section(&self) -> Option<&MemorySection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Memory(ref section) = section { return Some(section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Memory section, if any.
|
||||
pub fn memory_section(&self) -> Option<&MemorySection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Memory(ref section) = section { return Some(section); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Functions signatures section, if any.
|
||||
pub fn function_section(&self) -> Option<&FunctionSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Function(ref sect) = section { return Some(sect); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Functions signatures section, if any.
|
||||
pub fn function_section(&self) -> Option<&FunctionSection> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Function(ref sect) = section { return Some(sect); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Start section, if any.
|
||||
pub fn start_section(&self) -> Option<u32> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Start(sect) = section { return Some(sect); }
|
||||
}
|
||||
None
|
||||
}
|
||||
/// Start section, if any.
|
||||
pub fn start_section(&self) -> Option<u32> {
|
||||
for section in self.sections() {
|
||||
if let &Section::Start(sect) = section { return Some(sect); }
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Try to parse name section in place
|
||||
/// 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
|
||||
/// (index, Error) tuples of failed sections.
|
||||
pub fn parse_names(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> {
|
||||
let mut parse_errors = Vec::new();
|
||||
/// Try to parse name section in place
|
||||
/// 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
|
||||
/// (index, Error) tuples of failed sections.
|
||||
pub fn parse_names(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> {
|
||||
let mut parse_errors = Vec::new();
|
||||
|
||||
for i in 0..self.sections.len() {
|
||||
if let Some(name_section) = {
|
||||
let section = self.sections.get(i).expect("cannot fail because i in range 0..len; qed");
|
||||
if let Section::Custom(ref custom) = *section {
|
||||
if custom.name() == "name" {
|
||||
let mut rdr = io::Cursor::new(custom.payload());
|
||||
let name_section = match NameSection::deserialize(&self, &mut rdr) {
|
||||
Ok(ns) => ns,
|
||||
Err(e) => { parse_errors.push((i, e)); continue; }
|
||||
};
|
||||
Some(name_section)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else { None }
|
||||
} {
|
||||
*self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section);
|
||||
}
|
||||
}
|
||||
for i in 0..self.sections.len() {
|
||||
if let Some(name_section) = {
|
||||
let section = self.sections.get(i).expect("cannot fail because i in range 0..len; qed");
|
||||
if let Section::Custom(ref custom) = *section {
|
||||
if custom.name() == "name" {
|
||||
let mut rdr = io::Cursor::new(custom.payload());
|
||||
let name_section = match NameSection::deserialize(&self, &mut rdr) {
|
||||
Ok(ns) => ns,
|
||||
Err(e) => { parse_errors.push((i, e)); continue; }
|
||||
};
|
||||
Some(name_section)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else { None }
|
||||
} {
|
||||
*self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section);
|
||||
}
|
||||
}
|
||||
|
||||
if parse_errors.len() > 0 {
|
||||
Err((parse_errors, self))
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
if parse_errors.len() > 0 {
|
||||
Err((parse_errors, self))
|
||||
} else {
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Count imports by provided type
|
||||
pub fn import_count(&self, count_type: ImportCountType) -> usize {
|
||||
self.import_section()
|
||||
.map(|is|
|
||||
is.entries().iter().filter(|import| match (count_type, *import.external()) {
|
||||
(ImportCountType::Function, External::Function(_)) => true,
|
||||
(ImportCountType::Global, External::Global(_)) => true,
|
||||
_ => false
|
||||
}).count())
|
||||
.unwrap_or(0)
|
||||
}
|
||||
/// Count imports by provided type
|
||||
pub fn import_count(&self, count_type: ImportCountType) -> usize {
|
||||
self.import_section()
|
||||
.map(|is|
|
||||
is.entries().iter().filter(|import| match (count_type, *import.external()) {
|
||||
(ImportCountType::Function, External::Function(_)) => true,
|
||||
(ImportCountType::Global, External::Global(_)) => true,
|
||||
_ => false
|
||||
}).count())
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Query functions space
|
||||
pub fn functions_space(&self) -> usize {
|
||||
self.import_count(ImportCountType::Function) +
|
||||
self.function_section().map(|fs| fs.entries().len()).unwrap_or(0)
|
||||
}
|
||||
/// Query functions space
|
||||
pub fn functions_space(&self) -> usize {
|
||||
self.import_count(ImportCountType::Function) +
|
||||
self.function_section().map(|fs| fs.entries().len()).unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Query globals space
|
||||
pub fn globals_space(&self) -> usize {
|
||||
self.import_count(ImportCountType::Global) +
|
||||
self.global_section().map(|gs| gs.entries().len()).unwrap_or(0)
|
||||
}
|
||||
/// Query globals space
|
||||
pub fn globals_space(&self) -> usize {
|
||||
self.import_count(ImportCountType::Global) +
|
||||
self.global_section().map(|gs| gs.entries().len()).unwrap_or(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize for Module {
|
||||
type Error = super::Error;
|
||||
type Error = super::Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let mut sections = Vec::new();
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let mut sections = Vec::new();
|
||||
|
||||
let mut magic = [0u8; 4];
|
||||
reader.read(&mut magic)?;
|
||||
if magic != WASM_MAGIC_NUMBER {
|
||||
return Err(Error::InvalidMagic);
|
||||
}
|
||||
let mut magic = [0u8; 4];
|
||||
reader.read(&mut magic)?;
|
||||
if magic != WASM_MAGIC_NUMBER {
|
||||
return Err(Error::InvalidMagic);
|
||||
}
|
||||
|
||||
let version: u32 = Uint32::deserialize(reader)?.into();
|
||||
let version: u32 = Uint32::deserialize(reader)?.into();
|
||||
|
||||
if version != 1 {
|
||||
return Err(Error::UnsupportedVersion(version));
|
||||
}
|
||||
if version != 1 {
|
||||
return Err(Error::UnsupportedVersion(version));
|
||||
}
|
||||
|
||||
loop {
|
||||
match Section::deserialize(reader) {
|
||||
Err(Error::UnexpectedEof) => { break; },
|
||||
Err(e) => { return Err(e) },
|
||||
Ok(section) => { sections.push(section); }
|
||||
}
|
||||
}
|
||||
loop {
|
||||
match Section::deserialize(reader) {
|
||||
Err(Error::UnexpectedEof) => { break; },
|
||||
Err(e) => { return Err(e) },
|
||||
Ok(section) => { sections.push(section); }
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Module {
|
||||
magic: LittleEndian::read_u32(&magic),
|
||||
version: version,
|
||||
sections: sections,
|
||||
})
|
||||
}
|
||||
Ok(Module {
|
||||
magic: LittleEndian::read_u32(&magic),
|
||||
version: version,
|
||||
sections: sections,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Module {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> {
|
||||
Uint32::from(self.magic).serialize(w)?;
|
||||
Uint32::from(self.version).serialize(w)?;
|
||||
for section in self.sections.into_iter() {
|
||||
section.serialize(w)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> {
|
||||
Uint32::from(self.magic).serialize(w)?;
|
||||
Uint32::from(self.version).serialize(w)?;
|
||||
for section in self.sections.into_iter() {
|
||||
section.serialize(w)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct PeekSection<'a> {
|
||||
cursor: usize,
|
||||
region: &'a [u8],
|
||||
cursor: usize,
|
||||
region: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> io::Read for PeekSection<'a> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
|
||||
let available = ::std::cmp::min(buf.len(), self.region.len() - self.cursor);
|
||||
if available < buf.len() {
|
||||
return Err(::std::io::Error::from(::std::io::ErrorKind::UnexpectedEof));
|
||||
}
|
||||
fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
|
||||
let available = ::std::cmp::min(buf.len(), self.region.len() - self.cursor);
|
||||
if available < buf.len() {
|
||||
return Err(::std::io::Error::from(::std::io::ErrorKind::UnexpectedEof));
|
||||
}
|
||||
|
||||
let range = self.cursor..self.cursor + buf.len();
|
||||
buf.copy_from_slice(&self.region[range]);
|
||||
let range = self.cursor..self.cursor + buf.len();
|
||||
buf.copy_from_slice(&self.region[range]);
|
||||
|
||||
self.cursor += available;
|
||||
Ok(available)
|
||||
}
|
||||
self.cursor += available;
|
||||
Ok(available)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns size of the module in the provided stream
|
||||
pub fn peek_size(source: &[u8]) -> usize {
|
||||
if source.len() < 9 {
|
||||
return 0;
|
||||
}
|
||||
if source.len() < 9 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut cursor = 8;
|
||||
loop {
|
||||
let (new_cursor, section_id, section_len) = {
|
||||
let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] };
|
||||
let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) {
|
||||
Ok(res) => res.into(),
|
||||
Err(_) => { break; },
|
||||
};
|
||||
let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) {
|
||||
Ok(res) => res.into(),
|
||||
Err(_) => { break; },
|
||||
};
|
||||
let mut cursor = 8;
|
||||
loop {
|
||||
let (new_cursor, section_id, section_len) = {
|
||||
let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] };
|
||||
let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) {
|
||||
Ok(res) => res.into(),
|
||||
Err(_) => { break; },
|
||||
};
|
||||
let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) {
|
||||
Ok(res) => res.into(),
|
||||
Err(_) => { break; },
|
||||
};
|
||||
|
||||
(peek_section.cursor, section_id, section_len)
|
||||
};
|
||||
(peek_section.cursor, section_id, section_len)
|
||||
};
|
||||
|
||||
if section_id <= 11 && section_len > 0 {
|
||||
let next_cursor = cursor + new_cursor + section_len as usize;
|
||||
if next_cursor >= source.len() {
|
||||
break;
|
||||
}
|
||||
cursor = next_cursor;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if section_id <= 11 && section_len > 0 {
|
||||
let next_cursor = cursor + new_cursor + section_len as usize;
|
||||
if next_cursor >= source.len() {
|
||||
break;
|
||||
}
|
||||
cursor = next_cursor;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cursor
|
||||
cursor
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod integration_tests {
|
||||
|
||||
use super::super::{deserialize_file, serialize, deserialize_buffer, Section};
|
||||
use super::Module;
|
||||
use super::super::{deserialize_file, serialize, deserialize_buffer, Section};
|
||||
use super::Module;
|
||||
|
||||
#[test]
|
||||
fn hello() {
|
||||
let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");
|
||||
#[test]
|
||||
fn hello() {
|
||||
let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");
|
||||
|
||||
assert_eq!(module.version(), 1);
|
||||
assert_eq!(module.sections().len(), 8);
|
||||
}
|
||||
assert_eq!(module.version(), 1);
|
||||
assert_eq!(module.sections().len(), 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde() {
|
||||
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
let buf = serialize(module).expect("serialization to succeed");
|
||||
#[test]
|
||||
fn serde() {
|
||||
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
let buf = serialize(module).expect("serialization 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_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
|
||||
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]
|
||||
fn serde_type() {
|
||||
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
module.sections_mut().retain(|x| {
|
||||
if let &Section::Type(_) = x { true } else { false }
|
||||
});
|
||||
#[test]
|
||||
fn serde_type() {
|
||||
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
module.sections_mut().retain(|x| {
|
||||
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_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
assert_eq!(
|
||||
module_old.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"
|
||||
);
|
||||
}
|
||||
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");
|
||||
assert_eq!(
|
||||
module_old.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"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde_import() {
|
||||
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
module.sections_mut().retain(|x| {
|
||||
if let &Section::Import(_) = x { true } else { false }
|
||||
});
|
||||
#[test]
|
||||
fn serde_import() {
|
||||
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
module.sections_mut().retain(|x| {
|
||||
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_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
assert_eq!(
|
||||
module_old.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"
|
||||
);
|
||||
}
|
||||
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");
|
||||
assert_eq!(
|
||||
module_old.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"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde_code() {
|
||||
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
module.sections_mut().retain(|x| {
|
||||
if let &Section::Code(_) = x { true } else { false }
|
||||
});
|
||||
#[test]
|
||||
fn serde_code() {
|
||||
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
module.sections_mut().retain(|x| {
|
||||
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_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
assert_eq!(
|
||||
module_old.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"
|
||||
);
|
||||
}
|
||||
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");
|
||||
assert_eq!(
|
||||
module_old.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"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_() {
|
||||
use super::super::Opcode::*;
|
||||
#[test]
|
||||
fn const_() {
|
||||
use super::super::Opcode::*;
|
||||
|
||||
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];
|
||||
assert_eq!(func.code().elements().len(), 20);
|
||||
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];
|
||||
assert_eq!(func.code().elements().len(), 20);
|
||||
|
||||
assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]);
|
||||
assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]);
|
||||
assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]);
|
||||
assert_eq!(I64Const(-8192), func.code().elements()[3]);
|
||||
assert_eq!(I32Const(1024), func.code().elements()[4]);
|
||||
assert_eq!(I32Const(2048), func.code().elements()[5]);
|
||||
assert_eq!(I32Const(4096), func.code().elements()[6]);
|
||||
assert_eq!(I32Const(8192), func.code().elements()[7]);
|
||||
assert_eq!(I32Const(16384), func.code().elements()[8]);
|
||||
assert_eq!(I32Const(32767), func.code().elements()[9]);
|
||||
assert_eq!(I32Const(-1024), func.code().elements()[10]);
|
||||
assert_eq!(I32Const(-2048), func.code().elements()[11]);
|
||||
assert_eq!(I32Const(-4096), func.code().elements()[12]);
|
||||
assert_eq!(I32Const(-8192), func.code().elements()[13]);
|
||||
assert_eq!(I32Const(-16384), func.code().elements()[14]);
|
||||
assert_eq!(I32Const(-32768), func.code().elements()[15]);
|
||||
assert_eq!(I32Const(-2147483648), func.code().elements()[16]);
|
||||
assert_eq!(I32Const(2147483647), func.code().elements()[17]);
|
||||
}
|
||||
assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]);
|
||||
assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]);
|
||||
assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]);
|
||||
assert_eq!(I64Const(-8192), func.code().elements()[3]);
|
||||
assert_eq!(I32Const(1024), func.code().elements()[4]);
|
||||
assert_eq!(I32Const(2048), func.code().elements()[5]);
|
||||
assert_eq!(I32Const(4096), func.code().elements()[6]);
|
||||
assert_eq!(I32Const(8192), func.code().elements()[7]);
|
||||
assert_eq!(I32Const(16384), func.code().elements()[8]);
|
||||
assert_eq!(I32Const(32767), func.code().elements()[9]);
|
||||
assert_eq!(I32Const(-1024), func.code().elements()[10]);
|
||||
assert_eq!(I32Const(-2048), func.code().elements()[11]);
|
||||
assert_eq!(I32Const(-4096), func.code().elements()[12]);
|
||||
assert_eq!(I32Const(-8192), func.code().elements()[13]);
|
||||
assert_eq!(I32Const(-16384), func.code().elements()[14]);
|
||||
assert_eq!(I32Const(-32768), func.code().elements()[15]);
|
||||
assert_eq!(I32Const(-2147483648), func.code().elements()[16]);
|
||||
assert_eq!(I32Const(2147483647), func.code().elements()[17]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn store() {
|
||||
use super::super::Opcode::*;
|
||||
#[test]
|
||||
fn store() {
|
||||
use super::super::Opcode::*;
|
||||
|
||||
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 module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
|
||||
let func = &module.code_section().expect("Code section to exist").bodies()[0];
|
||||
|
||||
assert_eq!(func.code().elements().len(), 5);
|
||||
assert_eq!(I64Store(0, 32), func.code().elements()[2]);
|
||||
}
|
||||
assert_eq!(func.code().elements().len(), 5);
|
||||
assert_eq!(I64Store(0, 32), func.code().elements()[2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn peek() {
|
||||
use super::peek_size;
|
||||
#[test]
|
||||
fn peek() {
|
||||
use super::peek_size;
|
||||
|
||||
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
let mut buf = serialize(module).expect("serialization to succeed");
|
||||
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||
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]
|
||||
fn peek_2() {
|
||||
use super::peek_size;
|
||||
#[test]
|
||||
fn peek_2() {
|
||||
use super::peek_size;
|
||||
|
||||
let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
|
||||
let mut buf = serialize(module).expect("serialization to succeed");
|
||||
let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
|
||||
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]
|
||||
fn module_default_round_trip() {
|
||||
let module1 = Module::default();
|
||||
let buf = serialize(module1).expect("Serialization should succeed");
|
||||
#[test]
|
||||
fn module_default_round_trip() {
|
||||
let module1 = Module::default();
|
||||
let buf = serialize(module1).expect("Serialization should succeed");
|
||||
|
||||
let module2: Module = deserialize_buffer(&buf).expect("Deserialization should succeed");
|
||||
assert_eq!(Module::default().magic, module2.magic);
|
||||
}
|
||||
let module2: Module = deserialize_buffer(&buf).expect("Deserialization should succeed");
|
||||
assert_eq!(Module::default().magic, module2.magic);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn names() {
|
||||
use super::super::name_section::NameSection;
|
||||
#[test]
|
||||
fn names() {
|
||||
use super::super::name_section::NameSection;
|
||||
|
||||
let module = deserialize_file("./res/cases/v1/with_names.wasm")
|
||||
.expect("Should be deserialized")
|
||||
.parse_names()
|
||||
.expect("Names to be parsed");
|
||||
let module = deserialize_file("./res/cases/v1/with_names.wasm")
|
||||
.expect("Should be deserialized")
|
||||
.parse_names()
|
||||
.expect("Names to be parsed");
|
||||
|
||||
let mut found_section = false;
|
||||
for section in module.sections() {
|
||||
match *section {
|
||||
Section::Name(ref name_section) => {
|
||||
match *name_section {
|
||||
NameSection::Function(ref function_name_section) => {
|
||||
assert_eq!(
|
||||
function_name_section.names().get(0).expect("Should be entry #0"),
|
||||
"elog"
|
||||
);
|
||||
assert_eq!(
|
||||
function_name_section.names().get(11).expect("Should be entry #0"),
|
||||
"_ZN48_$LT$pwasm_token_contract..Endpoint$LT$T$GT$$GT$3new17hc3ace6dea0978cd9E"
|
||||
);
|
||||
let mut found_section = false;
|
||||
for section in module.sections() {
|
||||
match *section {
|
||||
Section::Name(ref name_section) => {
|
||||
match *name_section {
|
||||
NameSection::Function(ref function_name_section) => {
|
||||
assert_eq!(
|
||||
function_name_section.names().get(0).expect("Should be entry #0"),
|
||||
"elog"
|
||||
);
|
||||
assert_eq!(
|
||||
function_name_section.names().get(11).expect("Should be entry #0"),
|
||||
"_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");
|
||||
}
|
||||
}
|
||||
|
@ -10,218 +10,218 @@ const NAME_TYPE_LOCAL: u8 = 2;
|
||||
/// Debug name information.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum NameSection {
|
||||
/// Module name section.
|
||||
Module(ModuleNameSection),
|
||||
/// Module name section.
|
||||
Module(ModuleNameSection),
|
||||
|
||||
/// Function name section.
|
||||
Function(FunctionNameSection),
|
||||
/// Function name section.
|
||||
Function(FunctionNameSection),
|
||||
|
||||
/// Local name section.
|
||||
Local(LocalNameSection),
|
||||
/// Local name section.
|
||||
Local(LocalNameSection),
|
||||
|
||||
/// Name section is unparsed.
|
||||
Unparsed {
|
||||
/// The numeric identifier for this name section type.
|
||||
name_type: u8,
|
||||
/// The contents of this name section, unparsed.
|
||||
name_payload: Vec<u8>,
|
||||
},
|
||||
/// Name section is unparsed.
|
||||
Unparsed {
|
||||
/// The numeric identifier for this name section type.
|
||||
name_type: u8,
|
||||
/// The contents of this name section, unparsed.
|
||||
name_payload: Vec<u8>,
|
||||
},
|
||||
}
|
||||
|
||||
impl NameSection {
|
||||
/// Deserialize a name section.
|
||||
pub fn deserialize<R: Read>(
|
||||
module: &Module,
|
||||
rdr: &mut R,
|
||||
) -> Result<NameSection, Error> {
|
||||
let name_type: u8 = VarUint7::deserialize(rdr)?.into();
|
||||
let name_payload_len: u32 = VarUint32::deserialize(rdr)?.into();
|
||||
let name_section = match name_type {
|
||||
NAME_TYPE_MODULE => NameSection::Module(ModuleNameSection::deserialize(rdr)?),
|
||||
NAME_TYPE_FUNCTION => NameSection::Function(FunctionNameSection::deserialize(module, rdr)?),
|
||||
NAME_TYPE_LOCAL => NameSection::Local(LocalNameSection::deserialize(module, rdr)?),
|
||||
_ => {
|
||||
let mut name_payload = vec![0u8; name_payload_len as usize];
|
||||
rdr.read_exact(&mut name_payload)?;
|
||||
NameSection::Unparsed {
|
||||
name_type,
|
||||
name_payload,
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(name_section)
|
||||
}
|
||||
/// Deserialize a name section.
|
||||
pub fn deserialize<R: Read>(
|
||||
module: &Module,
|
||||
rdr: &mut R,
|
||||
) -> Result<NameSection, Error> {
|
||||
let name_type: u8 = VarUint7::deserialize(rdr)?.into();
|
||||
let name_payload_len: u32 = VarUint32::deserialize(rdr)?.into();
|
||||
let name_section = match name_type {
|
||||
NAME_TYPE_MODULE => NameSection::Module(ModuleNameSection::deserialize(rdr)?),
|
||||
NAME_TYPE_FUNCTION => NameSection::Function(FunctionNameSection::deserialize(module, rdr)?),
|
||||
NAME_TYPE_LOCAL => NameSection::Local(LocalNameSection::deserialize(module, rdr)?),
|
||||
_ => {
|
||||
let mut name_payload = vec![0u8; name_payload_len as usize];
|
||||
rdr.read_exact(&mut name_payload)?;
|
||||
NameSection::Unparsed {
|
||||
name_type,
|
||||
name_payload,
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(name_section)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for NameSection {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||
let (name_type, name_payload) = match self {
|
||||
NameSection::Module(mod_name) => {
|
||||
let mut buffer = vec![];
|
||||
mod_name.serialize(&mut buffer)?;
|
||||
(NAME_TYPE_MODULE, buffer)
|
||||
}
|
||||
NameSection::Function(fn_names) => {
|
||||
let mut buffer = vec![];
|
||||
fn_names.serialize(&mut buffer)?;
|
||||
(NAME_TYPE_FUNCTION, buffer)
|
||||
}
|
||||
NameSection::Local(local_names) => {
|
||||
let mut buffer = vec![];
|
||||
local_names.serialize(&mut buffer)?;
|
||||
(NAME_TYPE_LOCAL, buffer)
|
||||
}
|
||||
NameSection::Unparsed {
|
||||
name_type,
|
||||
name_payload,
|
||||
} => (name_type, name_payload),
|
||||
};
|
||||
VarUint7::from(name_type).serialize(wtr)?;
|
||||
VarUint32::from(name_payload.len()).serialize(wtr)?;
|
||||
wtr.write_all(&name_payload)?;
|
||||
Ok(())
|
||||
}
|
||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||
let (name_type, name_payload) = match self {
|
||||
NameSection::Module(mod_name) => {
|
||||
let mut buffer = vec![];
|
||||
mod_name.serialize(&mut buffer)?;
|
||||
(NAME_TYPE_MODULE, buffer)
|
||||
}
|
||||
NameSection::Function(fn_names) => {
|
||||
let mut buffer = vec![];
|
||||
fn_names.serialize(&mut buffer)?;
|
||||
(NAME_TYPE_FUNCTION, buffer)
|
||||
}
|
||||
NameSection::Local(local_names) => {
|
||||
let mut buffer = vec![];
|
||||
local_names.serialize(&mut buffer)?;
|
||||
(NAME_TYPE_LOCAL, buffer)
|
||||
}
|
||||
NameSection::Unparsed {
|
||||
name_type,
|
||||
name_payload,
|
||||
} => (name_type, name_payload),
|
||||
};
|
||||
VarUint7::from(name_type).serialize(wtr)?;
|
||||
VarUint32::from(name_payload.len()).serialize(wtr)?;
|
||||
wtr.write_all(&name_payload)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The name of this module.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ModuleNameSection {
|
||||
name: String,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl ModuleNameSection {
|
||||
/// Create a new module name section with the specified name.
|
||||
pub fn new<S: Into<String>>(name: S) -> ModuleNameSection {
|
||||
ModuleNameSection { name: name.into() }
|
||||
}
|
||||
/// Create a new module name section with the specified name.
|
||||
pub fn new<S: Into<String>>(name: S) -> ModuleNameSection {
|
||||
ModuleNameSection { name: name.into() }
|
||||
}
|
||||
|
||||
/// The name of this module.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
/// The name of this module.
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// The name of this module (mutable).
|
||||
pub fn name_mut(&mut self) -> &mut String {
|
||||
&mut self.name
|
||||
}
|
||||
/// The name of this module (mutable).
|
||||
pub fn name_mut(&mut self) -> &mut String {
|
||||
&mut self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ModuleNameSection {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||
self.name.serialize(wtr)
|
||||
}
|
||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||
self.name.serialize(wtr)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize for ModuleNameSection {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: Read>(rdr: &mut R) -> Result<ModuleNameSection, Error> {
|
||||
let name = String::deserialize(rdr)?;
|
||||
Ok(ModuleNameSection { name })
|
||||
}
|
||||
fn deserialize<R: Read>(rdr: &mut R) -> Result<ModuleNameSection, Error> {
|
||||
let name = String::deserialize(rdr)?;
|
||||
Ok(ModuleNameSection { name })
|
||||
}
|
||||
}
|
||||
|
||||
/// The names of the functions in this module.
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct FunctionNameSection {
|
||||
names: NameMap,
|
||||
names: NameMap,
|
||||
}
|
||||
|
||||
impl FunctionNameSection {
|
||||
/// A map from function indices to names.
|
||||
pub fn names(&self) -> &NameMap {
|
||||
&self.names
|
||||
}
|
||||
/// A map from function indices to names.
|
||||
pub fn names(&self) -> &NameMap {
|
||||
&self.names
|
||||
}
|
||||
|
||||
/// A map from function indices to names (mutable).
|
||||
pub fn names_mut(&mut self) -> &mut NameMap {
|
||||
&mut self.names
|
||||
}
|
||||
/// A map from function indices to names (mutable).
|
||||
pub fn names_mut(&mut self) -> &mut NameMap {
|
||||
&mut self.names
|
||||
}
|
||||
|
||||
/// Deserialize names, making sure that all names correspond to functions.
|
||||
pub fn deserialize<R: Read>(
|
||||
module: &Module,
|
||||
rdr: &mut R,
|
||||
) -> Result<FunctionNameSection, Error> {
|
||||
let names = IndexMap::deserialize(module.functions_space(), rdr)?;
|
||||
Ok(FunctionNameSection { names })
|
||||
}
|
||||
/// Deserialize names, making sure that all names correspond to functions.
|
||||
pub fn deserialize<R: Read>(
|
||||
module: &Module,
|
||||
rdr: &mut R,
|
||||
) -> Result<FunctionNameSection, Error> {
|
||||
let names = IndexMap::deserialize(module.functions_space(), rdr)?;
|
||||
Ok(FunctionNameSection { names })
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for FunctionNameSection {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||
self.names.serialize(wtr)
|
||||
}
|
||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||
self.names.serialize(wtr)
|
||||
}
|
||||
}
|
||||
|
||||
/// The names of the local variables in this module's functions.
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct LocalNameSection {
|
||||
local_names: IndexMap<NameMap>,
|
||||
local_names: IndexMap<NameMap>,
|
||||
}
|
||||
|
||||
impl LocalNameSection {
|
||||
/// A map from function indices to a map from variables indices to names.
|
||||
pub fn local_names(&self) -> &IndexMap<NameMap> {
|
||||
&self.local_names
|
||||
}
|
||||
/// A map from function indices to a map from variables indices to names.
|
||||
pub fn local_names(&self) -> &IndexMap<NameMap> {
|
||||
&self.local_names
|
||||
}
|
||||
|
||||
/// A map from function indices to a map from variables indices to names
|
||||
/// (mutable).
|
||||
pub fn local_names_mut(&mut self) -> &mut IndexMap<NameMap> {
|
||||
&mut self.local_names
|
||||
}
|
||||
/// A map from function indices to a map from variables indices to names
|
||||
/// (mutable).
|
||||
pub fn local_names_mut(&mut self) -> &mut IndexMap<NameMap> {
|
||||
&mut self.local_names
|
||||
}
|
||||
|
||||
/// Deserialize names, making sure that all names correspond to local
|
||||
/// variables.
|
||||
pub fn deserialize<R: Read>(
|
||||
module: &Module,
|
||||
rdr: &mut R,
|
||||
) -> Result<LocalNameSection, Error> {
|
||||
let funcs = module.function_section().ok_or_else(|| {
|
||||
Error::Other("cannot deserialize local names without a function section")
|
||||
})?;
|
||||
let max_entry_space = funcs.entries().len();
|
||||
/// Deserialize names, making sure that all names correspond to local
|
||||
/// variables.
|
||||
pub fn deserialize<R: Read>(
|
||||
module: &Module,
|
||||
rdr: &mut R,
|
||||
) -> Result<LocalNameSection, Error> {
|
||||
let funcs = module.function_section().ok_or_else(|| {
|
||||
Error::Other("cannot deserialize local names without a function section")
|
||||
})?;
|
||||
let max_entry_space = funcs.entries().len();
|
||||
|
||||
let max_signature_args = module
|
||||
.type_section()
|
||||
.map(|ts|
|
||||
ts.types()
|
||||
.iter()
|
||||
.map(|x| { let Type::Function(ref func) = *x; func.params().len() })
|
||||
.max()
|
||||
.unwrap_or(0))
|
||||
.unwrap_or(0);
|
||||
let max_signature_args = module
|
||||
.type_section()
|
||||
.map(|ts|
|
||||
ts.types()
|
||||
.iter()
|
||||
.map(|x| { let Type::Function(ref func) = *x; func.params().len() })
|
||||
.max()
|
||||
.unwrap_or(0))
|
||||
.unwrap_or(0);
|
||||
|
||||
let max_locals = module
|
||||
.code_section()
|
||||
.map(|cs| cs.bodies().iter().map(|f| f.locals().len()).max().unwrap_or(0))
|
||||
.unwrap_or(0);
|
||||
let max_locals = module
|
||||
.code_section()
|
||||
.map(|cs| cs.bodies().iter().map(|f| f.locals().len()).max().unwrap_or(0))
|
||||
.unwrap_or(0);
|
||||
|
||||
let max_space = max_signature_args + max_locals;
|
||||
let 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(
|
||||
max_entry_space,
|
||||
&deserialize_locals,
|
||||
rdr,
|
||||
)?;
|
||||
Ok(LocalNameSection { local_names })
|
||||
}}
|
||||
let local_names = IndexMap::deserialize_with(
|
||||
max_entry_space,
|
||||
&deserialize_locals,
|
||||
rdr,
|
||||
)?;
|
||||
Ok(LocalNameSection { local_names })
|
||||
}}
|
||||
|
||||
impl Serialize for LocalNameSection {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||
self.local_names.serialize(wtr)
|
||||
}
|
||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||
self.local_names.serialize(wtr)
|
||||
}
|
||||
}
|
||||
|
||||
/// A map from indices to names.
|
||||
@ -229,48 +229,48 @@ pub type NameMap = IndexMap<String>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::*;
|
||||
|
||||
// A helper funtion for the tests. Serialize a section, deserialize it,
|
||||
// and make sure it matches the original.
|
||||
fn serialize_test(original: NameSection) -> Vec<u8> {
|
||||
let mut buffer = vec![];
|
||||
original
|
||||
.serialize(&mut buffer)
|
||||
.expect("serialize error");
|
||||
buffer
|
||||
}
|
||||
// A helper funtion for the tests. Serialize a section, deserialize it,
|
||||
// and make sure it matches the original.
|
||||
fn serialize_test(original: NameSection) -> Vec<u8> {
|
||||
let mut buffer = vec![];
|
||||
original
|
||||
.serialize(&mut buffer)
|
||||
.expect("serialize error");
|
||||
buffer
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_module_name() {
|
||||
let original = NameSection::Module(ModuleNameSection::new("my_mod"));
|
||||
serialize_test(original.clone());
|
||||
}
|
||||
#[test]
|
||||
fn serialize_module_name() {
|
||||
let original = NameSection::Module(ModuleNameSection::new("my_mod"));
|
||||
serialize_test(original.clone());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_function_names() {
|
||||
let mut sect = FunctionNameSection::default();
|
||||
sect.names_mut().insert(0, "hello_world".to_string());
|
||||
serialize_test(NameSection::Function(sect));
|
||||
}
|
||||
#[test]
|
||||
fn serialize_function_names() {
|
||||
let mut sect = FunctionNameSection::default();
|
||||
sect.names_mut().insert(0, "hello_world".to_string());
|
||||
serialize_test(NameSection::Function(sect));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_local_names() {
|
||||
let mut sect = LocalNameSection::default();
|
||||
let mut locals = NameMap::default();
|
||||
locals.insert(0, "msg".to_string());
|
||||
sect.local_names_mut().insert(0, locals);
|
||||
serialize_test(NameSection::Local(sect));
|
||||
}
|
||||
#[test]
|
||||
fn serialize_local_names() {
|
||||
let mut sect = LocalNameSection::default();
|
||||
let mut locals = NameMap::default();
|
||||
locals.insert(0, "msg".to_string());
|
||||
sect.local_names_mut().insert(0, locals);
|
||||
serialize_test(NameSection::Local(sect));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_and_deserialize_unparsed() {
|
||||
let original = NameSection::Unparsed {
|
||||
// A made-up name section type which is unlikely to be allocated
|
||||
// soon, in order to allow us to test `Unparsed`.
|
||||
name_type: 120,
|
||||
name_payload: vec![0u8, 1, 2],
|
||||
};
|
||||
serialize_test(original.clone());
|
||||
}
|
||||
#[test]
|
||||
fn serialize_and_deserialize_unparsed() {
|
||||
let original = NameSection::Unparsed {
|
||||
// A made-up name section type which is unlikely to be allocated
|
||||
// soon, in order to allow us to test `Unparsed`.
|
||||
name_type: 120,
|
||||
name_payload: vec![0u8, 1, 2],
|
||||
};
|
||||
serialize_test(original.clone());
|
||||
}
|
||||
}
|
||||
|
2080
src/elements/ops.rs
2080
src/elements/ops.rs
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
@ -4,132 +4,132 @@ use super::{Deserialize, Serialize, Error, VarUint32, CountedList, InitExpr, Cou
|
||||
/// Entry in the element section.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ElementSegment {
|
||||
index: u32,
|
||||
offset: InitExpr,
|
||||
members: Vec<u32>,
|
||||
index: u32,
|
||||
offset: InitExpr,
|
||||
members: Vec<u32>,
|
||||
}
|
||||
|
||||
impl ElementSegment {
|
||||
/// New element segment.
|
||||
pub fn new(index: u32, offset: InitExpr, members: Vec<u32>) -> Self {
|
||||
ElementSegment { index: index, offset: offset, members: members }
|
||||
}
|
||||
/// New element segment.
|
||||
pub fn new(index: u32, offset: InitExpr, members: Vec<u32>) -> Self {
|
||||
ElementSegment { index: index, offset: offset, members: members }
|
||||
}
|
||||
|
||||
/// Sequence of function indices.
|
||||
pub fn members(&self) -> &[u32] { &self.members }
|
||||
/// Sequence of function indices.
|
||||
pub fn members(&self) -> &[u32] { &self.members }
|
||||
|
||||
/// Sequence of function indices (mutable)
|
||||
pub fn members_mut(&mut self) -> &mut Vec<u32> { &mut self.members }
|
||||
/// Sequence of function indices (mutable)
|
||||
pub fn members_mut(&mut self) -> &mut Vec<u32> { &mut self.members }
|
||||
|
||||
/// Table index (currently valid only value of `0`)
|
||||
pub fn index(&self) -> u32 { self.index }
|
||||
/// Table index (currently valid only value of `0`)
|
||||
pub fn index(&self) -> u32 { self.index }
|
||||
|
||||
/// An i32 initializer expression that computes the offset at which to place the elements.
|
||||
pub fn offset(&self) -> &InitExpr { &self.offset }
|
||||
/// An i32 initializer expression that computes the offset at which to place the elements.
|
||||
pub fn offset(&self) -> &InitExpr { &self.offset }
|
||||
|
||||
/// 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 }
|
||||
/// 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 }
|
||||
}
|
||||
|
||||
impl Deserialize for ElementSegment {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let index = VarUint32::deserialize(reader)?;
|
||||
let offset = InitExpr::deserialize(reader)?;
|
||||
let funcs: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
|
||||
.into_inner()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let index = VarUint32::deserialize(reader)?;
|
||||
let offset = InitExpr::deserialize(reader)?;
|
||||
let funcs: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
|
||||
.into_inner()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
|
||||
Ok(ElementSegment {
|
||||
index: index.into(),
|
||||
offset: offset,
|
||||
members: funcs,
|
||||
})
|
||||
}
|
||||
Ok(ElementSegment {
|
||||
index: index.into(),
|
||||
offset: offset,
|
||||
members: funcs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ElementSegment {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
VarUint32::from(self.index).serialize(writer)?;
|
||||
self.offset.serialize(writer)?;
|
||||
let data = self.members;
|
||||
let counted_list = CountedListWriter::<VarUint32, _>(
|
||||
data.len(),
|
||||
data.into_iter().map(Into::into),
|
||||
);
|
||||
counted_list.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
VarUint32::from(self.index).serialize(writer)?;
|
||||
self.offset.serialize(writer)?;
|
||||
let data = self.members;
|
||||
let counted_list = CountedListWriter::<VarUint32, _>(
|
||||
data.len(),
|
||||
data.into_iter().map(Into::into),
|
||||
);
|
||||
counted_list.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Data segment definition.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DataSegment {
|
||||
index: u32,
|
||||
offset: InitExpr,
|
||||
value: Vec<u8>,
|
||||
index: u32,
|
||||
offset: InitExpr,
|
||||
value: Vec<u8>,
|
||||
}
|
||||
|
||||
impl DataSegment {
|
||||
/// New data segments.
|
||||
pub fn new(index: u32, offset: InitExpr, value: Vec<u8>) -> Self {
|
||||
DataSegment {
|
||||
index: index,
|
||||
offset: offset,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
/// New data segments.
|
||||
pub fn new(index: u32, offset: InitExpr, value: Vec<u8>) -> Self {
|
||||
DataSegment {
|
||||
index: index,
|
||||
offset: offset,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
/// Linear memory index (currently the only valid value is `0`).
|
||||
pub fn index(&self) -> u32 { self.index }
|
||||
/// Linear memory index (currently the only valid value is `0`).
|
||||
pub fn index(&self) -> u32 { self.index }
|
||||
|
||||
/// An i32 initializer expression that computes the offset at which to place the data.
|
||||
pub fn offset(&self) -> &InitExpr { &self.offset }
|
||||
/// An i32 initializer expression that computes the offset at which to place the data.
|
||||
pub fn offset(&self) -> &InitExpr { &self.offset }
|
||||
|
||||
/// 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 }
|
||||
/// 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 }
|
||||
|
||||
/// Initial value of the data segment.
|
||||
pub fn value(&self) -> &[u8] { &self.value }
|
||||
/// Initial value of the data segment.
|
||||
pub fn value(&self) -> &[u8] { &self.value }
|
||||
|
||||
/// Initial value of the data segment (mutable).
|
||||
pub fn value_mut(&mut self) -> &mut Vec<u8> { &mut self.value }
|
||||
/// Initial value of the data segment (mutable).
|
||||
pub fn value_mut(&mut self) -> &mut Vec<u8> { &mut self.value }
|
||||
}
|
||||
|
||||
impl Deserialize for DataSegment {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let index = VarUint32::deserialize(reader)?;
|
||||
let offset = InitExpr::deserialize(reader)?;
|
||||
let value_len = VarUint32::deserialize(reader)?;
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let index = VarUint32::deserialize(reader)?;
|
||||
let offset = InitExpr::deserialize(reader)?;
|
||||
let value_len = VarUint32::deserialize(reader)?;
|
||||
|
||||
let mut value_buf = vec![0u8; value_len.into()];
|
||||
reader.read_exact(&mut value_buf[..])?;
|
||||
let mut value_buf = vec![0u8; value_len.into()];
|
||||
reader.read_exact(&mut value_buf[..])?;
|
||||
|
||||
Ok(DataSegment {
|
||||
index: index.into(),
|
||||
offset: offset,
|
||||
value: value_buf,
|
||||
})
|
||||
}
|
||||
Ok(DataSegment {
|
||||
index: index.into(),
|
||||
offset: offset,
|
||||
value: value_buf,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for DataSegment {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
VarUint32::from(self.index).serialize(writer)?;
|
||||
self.offset.serialize(writer)?;
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
VarUint32::from(self.index).serialize(writer)?;
|
||||
self.offset.serialize(writer)?;
|
||||
|
||||
let value = self.value;
|
||||
VarUint32::from(value.len()).serialize(writer)?;
|
||||
writer.write_all(&value[..])?;
|
||||
Ok(())
|
||||
}
|
||||
let value = self.value;
|
||||
VarUint32::from(value.len()).serialize(writer)?;
|
||||
writer.write_all(&value[..])?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,245 +1,245 @@
|
||||
use std::{io, fmt};
|
||||
use super::{
|
||||
Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint1, CountedList,
|
||||
CountedListWriter
|
||||
Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint1, CountedList,
|
||||
CountedListWriter
|
||||
};
|
||||
|
||||
/// Type definition in types section. Currently can be only of the function type.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Type {
|
||||
/// Function type.
|
||||
Function(FunctionType),
|
||||
/// Function type.
|
||||
Function(FunctionType),
|
||||
}
|
||||
|
||||
impl Deserialize for Type {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
Ok(Type::Function(FunctionType::deserialize(reader)?))
|
||||
}
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
Ok(Type::Function(FunctionType::deserialize(reader)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Type {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
match self {
|
||||
Type::Function(fn_type) => fn_type.serialize(writer)
|
||||
}
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
match self {
|
||||
Type::Function(fn_type) => fn_type.serialize(writer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Value type.
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum ValueType {
|
||||
/// 32-bit signed integer
|
||||
I32,
|
||||
/// 64-bit signed integer
|
||||
I64,
|
||||
/// 32-bit float
|
||||
F32,
|
||||
/// 64-bit float
|
||||
F64,
|
||||
/// 32-bit signed integer
|
||||
I32,
|
||||
/// 64-bit signed integer
|
||||
I64,
|
||||
/// 32-bit float
|
||||
F32,
|
||||
/// 64-bit float
|
||||
F64,
|
||||
}
|
||||
|
||||
impl Deserialize for ValueType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let val = VarInt7::deserialize(reader)?;
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let val = VarInt7::deserialize(reader)?;
|
||||
|
||||
match val.into() {
|
||||
-0x01 => Ok(ValueType::I32),
|
||||
-0x02 => Ok(ValueType::I64),
|
||||
-0x03 => Ok(ValueType::F32),
|
||||
-0x04 => Ok(ValueType::F64),
|
||||
_ => Err(Error::UnknownValueType(val.into())),
|
||||
}
|
||||
}
|
||||
match val.into() {
|
||||
-0x01 => Ok(ValueType::I32),
|
||||
-0x02 => Ok(ValueType::I64),
|
||||
-0x03 => Ok(ValueType::F32),
|
||||
-0x04 => Ok(ValueType::F64),
|
||||
_ => Err(Error::UnknownValueType(val.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ValueType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let val: VarInt7 = match self {
|
||||
ValueType::I32 => -0x01,
|
||||
ValueType::I64 => -0x02,
|
||||
ValueType::F32 => -0x03,
|
||||
ValueType::F64 => -0x04,
|
||||
}.into();
|
||||
val.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let val: VarInt7 = match self {
|
||||
ValueType::I32 => -0x01,
|
||||
ValueType::I64 => -0x02,
|
||||
ValueType::F32 => -0x03,
|
||||
ValueType::F64 => -0x04,
|
||||
}.into();
|
||||
val.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ValueType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ValueType::I32 => write!(f, "i32"),
|
||||
ValueType::I64 => write!(f, "i64"),
|
||||
ValueType::F32 => write!(f, "f32"),
|
||||
ValueType::F64 => write!(f, "f64"),
|
||||
}
|
||||
}
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
ValueType::I32 => write!(f, "i32"),
|
||||
ValueType::I64 => write!(f, "i64"),
|
||||
ValueType::F32 => write!(f, "f32"),
|
||||
ValueType::F64 => write!(f, "f64"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Block type which is basically `ValueType` + NoResult (to define blocks that have no return type)
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum BlockType {
|
||||
/// Value-type specified block type
|
||||
Value(ValueType),
|
||||
/// No specified block type
|
||||
NoResult,
|
||||
/// Value-type specified block type
|
||||
Value(ValueType),
|
||||
/// No specified block type
|
||||
NoResult,
|
||||
}
|
||||
|
||||
impl Deserialize for BlockType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let val = VarInt7::deserialize(reader)?;
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let val = VarInt7::deserialize(reader)?;
|
||||
|
||||
match val.into() {
|
||||
-0x01 => Ok(BlockType::Value(ValueType::I32)),
|
||||
-0x02 => Ok(BlockType::Value(ValueType::I64)),
|
||||
-0x03 => Ok(BlockType::Value(ValueType::F32)),
|
||||
-0x04 => Ok(BlockType::Value(ValueType::F64)),
|
||||
-0x40 => Ok(BlockType::NoResult),
|
||||
_ => Err(Error::UnknownValueType(val.into())),
|
||||
}
|
||||
}
|
||||
match val.into() {
|
||||
-0x01 => Ok(BlockType::Value(ValueType::I32)),
|
||||
-0x02 => Ok(BlockType::Value(ValueType::I64)),
|
||||
-0x03 => Ok(BlockType::Value(ValueType::F32)),
|
||||
-0x04 => Ok(BlockType::Value(ValueType::F64)),
|
||||
-0x40 => Ok(BlockType::NoResult),
|
||||
_ => Err(Error::UnknownValueType(val.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for BlockType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let val: VarInt7 = match self {
|
||||
BlockType::NoResult => -0x40i8,
|
||||
BlockType::Value(ValueType::I32) => -0x01,
|
||||
BlockType::Value(ValueType::I64) => -0x02,
|
||||
BlockType::Value(ValueType::F32) => -0x03,
|
||||
BlockType::Value(ValueType::F64) => -0x04,
|
||||
}.into();
|
||||
val.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let val: VarInt7 = match self {
|
||||
BlockType::NoResult => -0x40i8,
|
||||
BlockType::Value(ValueType::I32) => -0x01,
|
||||
BlockType::Value(ValueType::I64) => -0x02,
|
||||
BlockType::Value(ValueType::F32) => -0x03,
|
||||
BlockType::Value(ValueType::F64) => -0x04,
|
||||
}.into();
|
||||
val.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Function signature type.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct FunctionType {
|
||||
form: u8,
|
||||
params: Vec<ValueType>,
|
||||
return_type: Option<ValueType>,
|
||||
form: u8,
|
||||
params: Vec<ValueType>,
|
||||
return_type: Option<ValueType>,
|
||||
}
|
||||
|
||||
impl Default for FunctionType {
|
||||
fn default() -> Self {
|
||||
FunctionType {
|
||||
form: 0x60,
|
||||
params: Vec::new(),
|
||||
return_type: None,
|
||||
}
|
||||
}
|
||||
fn default() -> Self {
|
||||
FunctionType {
|
||||
form: 0x60,
|
||||
params: Vec::new(),
|
||||
return_type: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FunctionType {
|
||||
/// 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 {
|
||||
FunctionType {
|
||||
params: params,
|
||||
return_type: return_type,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
/// Function form (currently only valid value is `0x60`)
|
||||
pub fn form(&self) -> u8 { self.form }
|
||||
/// Parameters in the function signature.
|
||||
pub fn params(&self) -> &[ValueType] { &self.params }
|
||||
/// Mutable parameters in the function signature.
|
||||
pub fn params_mut(&mut self) -> &mut Vec<ValueType> { &mut self.params }
|
||||
/// Return type in the function signature, if any.
|
||||
pub fn return_type(&self) -> Option<ValueType> { self.return_type }
|
||||
/// Mutable type in the function signature, if any.
|
||||
pub fn return_type_mut(&mut self) -> &mut Option<ValueType> { &mut self.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 {
|
||||
FunctionType {
|
||||
params: params,
|
||||
return_type: return_type,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
/// Function form (currently only valid value is `0x60`)
|
||||
pub fn form(&self) -> u8 { self.form }
|
||||
/// Parameters in the function signature.
|
||||
pub fn params(&self) -> &[ValueType] { &self.params }
|
||||
/// Mutable parameters in the function signature.
|
||||
pub fn params_mut(&mut self) -> &mut Vec<ValueType> { &mut self.params }
|
||||
/// Return type in the function signature, if any.
|
||||
pub fn return_type(&self) -> Option<ValueType> { self.return_type }
|
||||
/// Mutable type in the function signature, if any.
|
||||
pub fn return_type_mut(&mut self) -> &mut Option<ValueType> { &mut self.return_type }
|
||||
}
|
||||
|
||||
impl Deserialize for FunctionType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let form: u8 = VarUint7::deserialize(reader)?.into();
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
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 return_type = if has_return_type.into() {
|
||||
Some(ValueType::deserialize(reader)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let has_return_type = VarUint1::deserialize(reader)?;
|
||||
let return_type = if has_return_type.into() {
|
||||
Some(ValueType::deserialize(reader)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(FunctionType {
|
||||
form: form,
|
||||
params: params,
|
||||
return_type: return_type,
|
||||
})
|
||||
}
|
||||
Ok(FunctionType {
|
||||
form: form,
|
||||
params: params,
|
||||
return_type: return_type,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for FunctionType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
VarUint7::from(self.form).serialize(writer)?;
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
VarUint7::from(self.form).serialize(writer)?;
|
||||
|
||||
let data = self.params;
|
||||
let counted_list = CountedListWriter::<ValueType, _>(
|
||||
data.len(),
|
||||
data.into_iter().map(Into::into),
|
||||
);
|
||||
counted_list.serialize(writer)?;
|
||||
let data = self.params;
|
||||
let counted_list = CountedListWriter::<ValueType, _>(
|
||||
data.len(),
|
||||
data.into_iter().map(Into::into),
|
||||
);
|
||||
counted_list.serialize(writer)?;
|
||||
|
||||
if let Some(return_type) = self.return_type {
|
||||
VarUint1::from(true).serialize(writer)?;
|
||||
return_type.serialize(writer)?;
|
||||
} else {
|
||||
VarUint1::from(false).serialize(writer)?;
|
||||
}
|
||||
if let Some(return_type) = self.return_type {
|
||||
VarUint1::from(true).serialize(writer)?;
|
||||
return_type.serialize(writer)?;
|
||||
} else {
|
||||
VarUint1::from(false).serialize(writer)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Table element type.
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum TableElementType {
|
||||
/// A reference to a function with any signature.
|
||||
AnyFunc,
|
||||
/// A reference to a function with any signature.
|
||||
AnyFunc,
|
||||
}
|
||||
|
||||
impl Deserialize for TableElementType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let val = VarInt7::deserialize(reader)?;
|
||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||
let val = VarInt7::deserialize(reader)?;
|
||||
|
||||
match val.into() {
|
||||
-0x10 => Ok(TableElementType::AnyFunc),
|
||||
_ => Err(Error::UnknownTableElementType(val.into())),
|
||||
}
|
||||
}
|
||||
match val.into() {
|
||||
-0x10 => Ok(TableElementType::AnyFunc),
|
||||
_ => Err(Error::UnknownTableElementType(val.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for TableElementType {
|
||||
type Error = Error;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let val: VarInt7 = match self {
|
||||
TableElementType::AnyFunc => 0x70,
|
||||
}.into();
|
||||
val.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||
let val: VarInt7 = match self {
|
||||
TableElementType::AnyFunc => 0x70,
|
||||
}.into();
|
||||
val.serialize(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
20
src/lib.rs
20
src/lib.rs
@ -14,18 +14,18 @@ mod validation;
|
||||
mod common;
|
||||
|
||||
pub use elements::{
|
||||
Error as SerializationError,
|
||||
deserialize_buffer,
|
||||
deserialize_file,
|
||||
serialize,
|
||||
serialize_to_file,
|
||||
peek_size,
|
||||
Error as SerializationError,
|
||||
deserialize_buffer,
|
||||
deserialize_file,
|
||||
serialize,
|
||||
serialize_to_file,
|
||||
peek_size,
|
||||
};
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub use interpreter::{
|
||||
ProgramInstance,
|
||||
ModuleInstance,
|
||||
ModuleInstanceInterface,
|
||||
RuntimeValue,
|
||||
ProgramInstance,
|
||||
ModuleInstance,
|
||||
ModuleInstanceInterface,
|
||||
RuntimeValue,
|
||||
};
|
||||
|
Reference in New Issue
Block a user