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() {
|
fn main() {
|
||||||
|
|
||||||
// Example binary accepts one parameter which is the output file
|
// Example binary accepts one parameter which is the output file
|
||||||
// where generated wasm module will be written at the end of execution
|
// where generated wasm module will be written at the end of execution
|
||||||
let args = env::args().collect::<Vec<_>>();
|
let args = env::args().collect::<Vec<_>>();
|
||||||
if args.len() != 2 {
|
if args.len() != 2 {
|
||||||
println!("Usage: {} output_file.wasm", args[0]);
|
println!("Usage: {} output_file.wasm", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main entry for the builder api is the module function
|
// Main entry for the builder api is the module function
|
||||||
// It returns empty module builder structure which can be further
|
// It returns empty module builder structure which can be further
|
||||||
// appended with various wasm artefacts
|
// appended with various wasm artefacts
|
||||||
let module = builder::module()
|
let module = builder::module()
|
||||||
// Here we append function to the builder
|
// Here we append function to the builder
|
||||||
// function() function returns a function builder attached
|
// function() function returns a function builder attached
|
||||||
// to the module builder.
|
// to the module builder.
|
||||||
.function()
|
.function()
|
||||||
// We describe signature for the function via signature()
|
// We describe signature for the function via signature()
|
||||||
// function. In our simple example it's just one input
|
// function. In our simple example it's just one input
|
||||||
// argument of type 'i32' without return value
|
// argument of type 'i32' without return value
|
||||||
.signature().with_param(elements::ValueType::I32).build()
|
.signature().with_param(elements::ValueType::I32).build()
|
||||||
// body() without any further arguments means that the body
|
// body() without any further arguments means that the body
|
||||||
// of the function will be empty
|
// of the function will be empty
|
||||||
.body().build()
|
.body().build()
|
||||||
// This is the end of the function builder. When `build()` is
|
// This is the end of the function builder. When `build()` is
|
||||||
// invoked, function builder returns original module builder
|
// invoked, function builder returns original module builder
|
||||||
// from which it was invoked
|
// from which it was invoked
|
||||||
.build()
|
.build()
|
||||||
// And finally we finish our module builder to produce actual
|
// And finally we finish our module builder to produce actual
|
||||||
// wasm module.
|
// wasm module.
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Module structure can be serialzed to produce a valid wasm file
|
// Module structure can be serialzed to produce a valid wasm file
|
||||||
parity_wasm::serialize_to_file(&args[1], module).unwrap();
|
parity_wasm::serialize_to_file(&args[1], module).unwrap();
|
||||||
}
|
}
|
@ -7,40 +7,40 @@ use std::env;
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
// Example executable takes one argument which must
|
// Example executable takes one argument which must
|
||||||
// refernce the existing file with a valid wasm module
|
// refernce the existing file with a valid wasm module
|
||||||
let args = env::args().collect::<Vec<_>>();
|
let args = env::args().collect::<Vec<_>>();
|
||||||
if args.len() != 2 {
|
if args.len() != 2 {
|
||||||
println!("Usage: {} somefile.wasm", args[0]);
|
println!("Usage: {} somefile.wasm", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we load module using dedicated for this purpose
|
// Here we load module using dedicated for this purpose
|
||||||
// `deserialize_file` function (which works only with modules)
|
// `deserialize_file` function (which works only with modules)
|
||||||
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
||||||
|
|
||||||
// We query module for data section. Note that not every valid
|
// We query module for data section. Note that not every valid
|
||||||
// wasm module must contain a data section. So in case the provided
|
// wasm module must contain a data section. So in case the provided
|
||||||
// module does not contain data section, we panic with an error
|
// module does not contain data section, we panic with an error
|
||||||
let data_section = module.data_section().expect("no data section in module");
|
let data_section = module.data_section().expect("no data section in module");
|
||||||
|
|
||||||
// Printing the total count of data segments
|
// Printing the total count of data segments
|
||||||
println!("Data segments: {}", data_section.entries().len());
|
println!("Data segments: {}", data_section.entries().len());
|
||||||
|
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
for entry in data_section.entries() {
|
for entry in data_section.entries() {
|
||||||
// Printing the details info of each data segment
|
// Printing the details info of each data segment
|
||||||
// see `elements::DataSegment` for more properties
|
// see `elements::DataSegment` for more properties
|
||||||
// you can query
|
// you can query
|
||||||
println!(" Entry #{}", index);
|
println!(" Entry #{}", index);
|
||||||
|
|
||||||
// This shows the initialization member of data segment
|
// This shows the initialization member of data segment
|
||||||
// (expression which must resolve in the linear memory location).
|
// (expression which must resolve in the linear memory location).
|
||||||
println!(" init: {}", entry.offset().code()[0]);
|
println!(" init: {}", entry.offset().code()[0]);
|
||||||
|
|
||||||
// This shows the total length of the data segment in bytes.
|
// This shows the total length of the data segment in bytes.
|
||||||
println!(" size: {}", entry.value().len());
|
println!(" size: {}", entry.value().len());
|
||||||
|
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,74 +10,74 @@ use parity_wasm::elements::{Internal, External, Type, FunctionType, Module};
|
|||||||
// Auxillary function to resolve function type (signature) given it's callable index
|
// Auxillary function to resolve function type (signature) given it's callable index
|
||||||
fn type_by_index(module: &Module, index: usize) -> FunctionType {
|
fn type_by_index(module: &Module, index: usize) -> FunctionType {
|
||||||
|
|
||||||
// Demand that function and type section exist. Otherwise, fail with a
|
// Demand that function and type section exist. Otherwise, fail with a
|
||||||
// corresponding error.
|
// corresponding error.
|
||||||
let function_section = module.function_section().expect("No function section found");
|
let function_section = module.function_section().expect("No function section found");
|
||||||
let type_section = module.type_section().expect("No type section found");
|
let type_section = module.type_section().expect("No type section found");
|
||||||
|
|
||||||
// This counts the number of _function_ imports listed by the module, excluding
|
// This counts the number of _function_ imports listed by the module, excluding
|
||||||
// the globals, since indexing for actual functions for `call` and `export` purposes
|
// the globals, since indexing for actual functions for `call` and `export` purposes
|
||||||
// includes both imported and own functions. So we actualy need the imported function count
|
// includes both imported and own functions. So we actualy need the imported function count
|
||||||
// to resolve actual index of the given function in own functions list.
|
// to resolve actual index of the given function in own functions list.
|
||||||
let import_section_len: usize = match module.import_section() {
|
let import_section_len: usize = match module.import_section() {
|
||||||
Some(import) =>
|
Some(import) =>
|
||||||
import.entries().iter().filter(|entry| match entry.external() {
|
import.entries().iter().filter(|entry| match entry.external() {
|
||||||
&External::Function(_) => true,
|
&External::Function(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}).count(),
|
}).count(),
|
||||||
None => 0,
|
None => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Substract the value queried in the previous step from the provided index
|
// Substract the value queried in the previous step from the provided index
|
||||||
// to get own function index from which we can query type next.
|
// to get own function index from which we can query type next.
|
||||||
let function_index_in_section = index - import_section_len;
|
let function_index_in_section = index - import_section_len;
|
||||||
|
|
||||||
// Query the own function given we have it's index
|
// Query the own function given we have it's index
|
||||||
let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize;
|
let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize;
|
||||||
|
|
||||||
// Finally, return function type (signature)
|
// Finally, return function type (signature)
|
||||||
match type_section.types()[func_type_ref] {
|
match type_section.types()[func_type_ref] {
|
||||||
Type::Function(ref func_type) => func_type.clone(),
|
Type::Function(ref func_type) => func_type.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
// Example executable takes one argument which must
|
// Example executable takes one argument which must
|
||||||
// refernce the existing file with a valid wasm module
|
// refernce the existing file with a valid wasm module
|
||||||
let args: Vec<_> = args().collect();
|
let args: Vec<_> = args().collect();
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
println!("Prints export function names with and their types");
|
println!("Prints export function names with and their types");
|
||||||
println!("Usage: {} <wasm file>", args[0]);
|
println!("Usage: {} <wasm file>", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we load module using dedicated for this purpose
|
// Here we load module using dedicated for this purpose
|
||||||
// `deserialize_file` function (which works only with modules)
|
// `deserialize_file` function (which works only with modules)
|
||||||
let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized");
|
let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized");
|
||||||
|
|
||||||
// Query the export section from the loaded module. Note that not every
|
// Query the export section from the loaded module. Note that not every
|
||||||
// wasm module obliged to contain export section. So in case there is no
|
// wasm module obliged to contain export section. So in case there is no
|
||||||
// any export section, we panic with the corresponding error.
|
// any export section, we panic with the corresponding error.
|
||||||
let export_section = module.export_section().expect("No export section found");
|
let export_section = module.export_section().expect("No export section found");
|
||||||
|
|
||||||
// Process all exports, leaving only those which reference the internal function
|
// Process all exports, leaving only those which reference the internal function
|
||||||
// of the wasm module
|
// of the wasm module
|
||||||
let exports: Vec<String> = export_section.entries().iter()
|
let exports: Vec<String> = export_section.entries().iter()
|
||||||
.filter_map(|entry|
|
.filter_map(|entry|
|
||||||
// This is match on export variant, which can be function, global,table or memory
|
// This is match on export variant, which can be function, global,table or memory
|
||||||
// We are interested only in functions for an example
|
// We are interested only in functions for an example
|
||||||
match *entry.internal() {
|
match *entry.internal() {
|
||||||
// Return function export name (return by field() function and it's index)
|
// Return function export name (return by field() function and it's index)
|
||||||
Internal::Function(index) => Some((entry.field(), index as usize)),
|
Internal::Function(index) => Some((entry.field(), index as usize)),
|
||||||
_ => None
|
_ => None
|
||||||
})
|
})
|
||||||
// Another map to resolve function signature index given it's internal index and return
|
// Another map to resolve function signature index given it's internal index and return
|
||||||
// the printable string of the export
|
// the printable string of the export
|
||||||
.map(|(field, index)| format!("{:}: {:?}", field, type_by_index(&module, index).params())).collect();
|
.map(|(field, index)| format!("{:}: {:?}", field, type_by_index(&module, index).params())).collect();
|
||||||
|
|
||||||
// Print the result
|
// Print the result
|
||||||
for export in exports {
|
for export in exports {
|
||||||
println!("{:}", export);
|
println!("{:}", export);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,40 +4,40 @@ use std::env;
|
|||||||
use parity_wasm::elements::Section;
|
use parity_wasm::elements::Section;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = env::args().collect::<Vec<_>>();
|
let args = env::args().collect::<Vec<_>>();
|
||||||
if args.len() != 2 {
|
if args.len() != 2 {
|
||||||
println!("Usage: {} somefile.wasm", args[0]);
|
println!("Usage: {} somefile.wasm", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
||||||
|
|
||||||
println!("Module sections: {}", module.sections().len());
|
println!("Module sections: {}", module.sections().len());
|
||||||
|
|
||||||
for section in module.sections() {
|
for section in module.sections() {
|
||||||
match *section {
|
match *section {
|
||||||
Section::Import(ref import_section) => {
|
Section::Import(ref import_section) => {
|
||||||
println!(" Imports: {}", import_section.entries().len());
|
println!(" Imports: {}", import_section.entries().len());
|
||||||
import_section.entries().iter().map(|e| println!(" {}.{}", e.module(), e.field())).count();
|
import_section.entries().iter().map(|e| println!(" {}.{}", e.module(), e.field())).count();
|
||||||
},
|
},
|
||||||
Section::Export(ref exports_section) => {
|
Section::Export(ref exports_section) => {
|
||||||
println!(" Exports: {}", exports_section.entries().len());
|
println!(" Exports: {}", exports_section.entries().len());
|
||||||
exports_section.entries().iter().map(|e| println!(" {}", e.field())).count();
|
exports_section.entries().iter().map(|e| println!(" {}", e.field())).count();
|
||||||
},
|
},
|
||||||
Section::Function(ref function_section) => {
|
Section::Function(ref function_section) => {
|
||||||
println!(" Functions: {}", function_section.entries().len());
|
println!(" Functions: {}", function_section.entries().len());
|
||||||
},
|
},
|
||||||
Section::Type(ref type_section) => {
|
Section::Type(ref type_section) => {
|
||||||
println!(" Types: {}", type_section.types().len());
|
println!(" Types: {}", type_section.types().len());
|
||||||
},
|
},
|
||||||
Section::Global(ref globals_section) => {
|
Section::Global(ref globals_section) => {
|
||||||
println!(" Globals: {}", globals_section.entries().len());
|
println!(" Globals: {}", globals_section.entries().len());
|
||||||
},
|
},
|
||||||
Section::Data(ref data_section) if data_section.entries().len() > 0 => {
|
Section::Data(ref data_section) if data_section.entries().len() > 0 => {
|
||||||
let data = &data_section.entries()[0];
|
let data = &data_section.entries()[0];
|
||||||
println!(" Data size: {}", data.value().len());
|
println!(" Data size: {}", data.value().len());
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,58 +6,58 @@ use parity_wasm::elements;
|
|||||||
use parity_wasm::builder;
|
use parity_wasm::builder;
|
||||||
|
|
||||||
pub fn inject_nop(opcodes: &mut elements::Opcodes) {
|
pub fn inject_nop(opcodes: &mut elements::Opcodes) {
|
||||||
use parity_wasm::elements::Opcode::*;
|
use parity_wasm::elements::Opcode::*;
|
||||||
let opcodes = opcodes.elements_mut();
|
let opcodes = opcodes.elements_mut();
|
||||||
let mut position = 0;
|
let mut position = 0;
|
||||||
loop {
|
loop {
|
||||||
let need_inject = match &opcodes[position] {
|
let need_inject = match &opcodes[position] {
|
||||||
&Block(_) | &If(_) => true,
|
&Block(_) | &If(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if need_inject {
|
if need_inject {
|
||||||
opcodes.insert(position + 1, Nop);
|
opcodes.insert(position + 1, Nop);
|
||||||
}
|
}
|
||||||
|
|
||||||
position += 1;
|
position += 1;
|
||||||
if position >= opcodes.len() {
|
if position >= opcodes.len() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = env::args().collect::<Vec<_>>();
|
let args = env::args().collect::<Vec<_>>();
|
||||||
if args.len() != 3 {
|
if args.len() != 3 {
|
||||||
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
|
println!("Usage: {} input_file.wasm output_file.wasm", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut module = parity_wasm::deserialize_file(&args[1]).unwrap();
|
let mut module = parity_wasm::deserialize_file(&args[1]).unwrap();
|
||||||
|
|
||||||
for section in module.sections_mut() {
|
for section in module.sections_mut() {
|
||||||
match section {
|
match section {
|
||||||
&mut elements::Section::Code(ref mut code_section) => {
|
&mut elements::Section::Code(ref mut code_section) => {
|
||||||
for ref mut func_body in code_section.bodies_mut() {
|
for ref mut func_body in code_section.bodies_mut() {
|
||||||
inject_nop(func_body.code_mut());
|
inject_nop(func_body.code_mut());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => { }
|
_ => { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut build = builder::from_module(module);
|
let mut build = builder::from_module(module);
|
||||||
let import_sig = build.push_signature(
|
let import_sig = build.push_signature(
|
||||||
builder::signature()
|
builder::signature()
|
||||||
.param().i32()
|
.param().i32()
|
||||||
.param().i32()
|
.param().i32()
|
||||||
.return_type().i32()
|
.return_type().i32()
|
||||||
.build_sig()
|
.build_sig()
|
||||||
);
|
);
|
||||||
let build = build.import()
|
let build = build.import()
|
||||||
.module("env")
|
.module("env")
|
||||||
.field("log")
|
.field("log")
|
||||||
.external().func(import_sig)
|
.external().func(import_sig)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
parity_wasm::serialize_to_file(&args[2], build.build()).unwrap();
|
parity_wasm::serialize_to_file(&args[2], build.build()).unwrap();
|
||||||
}
|
}
|
@ -7,30 +7,30 @@ use std::env::args;
|
|||||||
use parity_wasm::ModuleInstanceInterface;
|
use parity_wasm::ModuleInstanceInterface;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<_> = args().collect();
|
let args: Vec<_> = args().collect();
|
||||||
if args.len() != 3 {
|
if args.len() != 3 {
|
||||||
println!("Usage: {} <wasm file> <arg>", args[0]);
|
println!("Usage: {} <wasm file> <arg>", args[0]);
|
||||||
println!(" wasm file should contain exported `_call` function with single I32 argument");
|
println!(" wasm file should contain exported `_call` function with single I32 argument");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intrepreter initialization.
|
// Intrepreter initialization.
|
||||||
let program = parity_wasm::ProgramInstance::new();
|
let program = parity_wasm::ProgramInstance::new();
|
||||||
|
|
||||||
// Here we load module using dedicated for this purpose
|
// Here we load module using dedicated for this purpose
|
||||||
// `deserialize_file` function (which works only with modules)
|
// `deserialize_file` function (which works only with modules)
|
||||||
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
let module = parity_wasm::deserialize_file(&args[1]).expect("Failed to load module");
|
||||||
|
|
||||||
// Intialize deserialized module. It adds module into It expects 3 parameters:
|
// Intialize deserialized module. It adds module into It expects 3 parameters:
|
||||||
// - a name for the module
|
// - a name for the module
|
||||||
// - a module declaration
|
// - a module declaration
|
||||||
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
|
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
|
||||||
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
|
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
|
||||||
let module = program.add_module("main", module, None).expect("Failed to initialize module");
|
let module = program.add_module("main", module, None).expect("Failed to initialize module");
|
||||||
|
|
||||||
// The argument should be parsable as a valid integer
|
// The argument should be parsable as a valid integer
|
||||||
let argument: i32 = args[2].parse().expect("Integer argument required");
|
let argument: i32 = args[2].parse().expect("Integer argument required");
|
||||||
|
|
||||||
// "_call" export of function to be executed with an i32 argument and prints the result of execution
|
// "_call" export of function to be executed with an i32 argument and prints the result of execution
|
||||||
println!("Result: {:?}", module.execute_export("_call", vec![parity_wasm::RuntimeValue::I32(argument)].into()));
|
println!("Result: {:?}", module.execute_export("_call", vec![parity_wasm::RuntimeValue::I32(argument)].into()));
|
||||||
}
|
}
|
||||||
|
@ -5,80 +5,79 @@ use std::env::args;
|
|||||||
use parity_wasm::{interpreter, ModuleInstanceInterface, RuntimeValue};
|
use parity_wasm::{interpreter, ModuleInstanceInterface, RuntimeValue};
|
||||||
use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType};
|
use parity_wasm::elements::{Internal, External, Type, FunctionType, ValueType};
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<_> = args().collect();
|
let args: Vec<_> = args().collect();
|
||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
println!("Usage: {} <wasm file> <exported func> [<arg>...]", args[0]);
|
println!("Usage: {} <wasm file> <exported func> [<arg>...]", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let func_name = &args[2];
|
let func_name = &args[2];
|
||||||
let (_, program_args) = args.split_at(3);
|
let (_, program_args) = args.split_at(3);
|
||||||
|
|
||||||
// Intrepreter initialization.
|
// Intrepreter initialization.
|
||||||
let program = parity_wasm::ProgramInstance::new();
|
let program = parity_wasm::ProgramInstance::new();
|
||||||
|
|
||||||
let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized");
|
let module = parity_wasm::deserialize_file(&args[1]).expect("File to be deserialized");
|
||||||
|
|
||||||
// Extracts call arguments from command-line arguments
|
// Extracts call arguments from command-line arguments
|
||||||
let execution_params = {
|
let execution_params = {
|
||||||
// Export section has an entry with a func_name with an index inside a module
|
// Export section has an entry with a func_name with an index inside a module
|
||||||
let export_section = module.export_section().expect("No export section found");
|
let export_section = module.export_section().expect("No export section found");
|
||||||
// It's a section with function declarations (which are references to the type section entries)
|
// It's a section with function declarations (which are references to the type section entries)
|
||||||
let function_section = module.function_section().expect("No function section found");
|
let function_section = module.function_section().expect("No function section found");
|
||||||
// Type section stores function types which are referenced by function_section entries
|
// Type section stores function types which are referenced by function_section entries
|
||||||
let type_section = module.type_section().expect("No type section found");
|
let type_section = module.type_section().expect("No type section found");
|
||||||
|
|
||||||
// Given function name used to find export section entry which contains
|
// Given function name used to find export section entry which contains
|
||||||
// an `internal` field which points to the index in the function index space
|
// an `internal` field which points to the index in the function index space
|
||||||
let found_entry = export_section.entries().iter()
|
let found_entry = export_section.entries().iter()
|
||||||
.find(|entry| func_name == entry.field()).expect(&format!("No export with name {} found", func_name));
|
.find(|entry| func_name == entry.field()).expect(&format!("No export with name {} found", func_name));
|
||||||
|
|
||||||
// Function index in the function index space (internally-defined + imported)
|
// Function index in the function index space (internally-defined + imported)
|
||||||
let function_index: usize = match found_entry.internal() {
|
let function_index: usize = match found_entry.internal() {
|
||||||
&Internal::Function(index) => index as usize,
|
&Internal::Function(index) => index as usize,
|
||||||
_ => panic!("Founded export is not a function"),
|
_ => panic!("Founded export is not a function"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// We need to count import section entries (functions only!) to subtract it from function_index
|
// We need to count import section entries (functions only!) to subtract it from function_index
|
||||||
// and obtain the index within the function section
|
// and obtain the index within the function section
|
||||||
let import_section_len: usize = match module.import_section() {
|
let import_section_len: usize = match module.import_section() {
|
||||||
Some(import) =>
|
Some(import) =>
|
||||||
import.entries().iter().filter(|entry| match entry.external() {
|
import.entries().iter().filter(|entry| match entry.external() {
|
||||||
&External::Function(_) => true,
|
&External::Function(_) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}).count(),
|
}).count(),
|
||||||
None => 0,
|
None => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculates a function index within module's function section
|
// Calculates a function index within module's function section
|
||||||
let function_index_in_section = function_index - import_section_len;
|
let function_index_in_section = function_index - import_section_len;
|
||||||
|
|
||||||
// Getting a type reference from a function section entry
|
// Getting a type reference from a function section entry
|
||||||
let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize;
|
let func_type_ref: usize = function_section.entries()[function_index_in_section].type_ref() as usize;
|
||||||
|
|
||||||
// Use the reference to get an actual function type
|
// Use the reference to get an actual function type
|
||||||
let function_type: &FunctionType = match &type_section.types()[func_type_ref] {
|
let function_type: &FunctionType = match &type_section.types()[func_type_ref] {
|
||||||
&Type::Function(ref func_type) => func_type,
|
&Type::Function(ref func_type) => func_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parses arguments and constructs runtime values in correspondence of their types
|
// Parses arguments and constructs runtime values in correspondence of their types
|
||||||
let args: Vec<RuntimeValue> = function_type.params().iter().enumerate().map(|(i, value)| match value {
|
let args: Vec<RuntimeValue> = function_type.params().iter().enumerate().map(|(i, value)| match value {
|
||||||
&ValueType::I32 => RuntimeValue::I32(program_args[i].parse::<i32>().expect(&format!("Can't parse arg #{} as i32", program_args[i]))),
|
&ValueType::I32 => RuntimeValue::I32(program_args[i].parse::<i32>().expect(&format!("Can't parse arg #{} as i32", program_args[i]))),
|
||||||
&ValueType::I64 => RuntimeValue::I64(program_args[i].parse::<i64>().expect(&format!("Can't parse arg #{} as i64", program_args[i]))),
|
&ValueType::I64 => RuntimeValue::I64(program_args[i].parse::<i64>().expect(&format!("Can't parse arg #{} as i64", program_args[i]))),
|
||||||
&ValueType::F32 => RuntimeValue::F32(program_args[i].parse::<f32>().expect(&format!("Can't parse arg #{} as f32", program_args[i]))),
|
&ValueType::F32 => RuntimeValue::F32(program_args[i].parse::<f32>().expect(&format!("Can't parse arg #{} as f32", program_args[i]))),
|
||||||
&ValueType::F64 => RuntimeValue::F64(program_args[i].parse::<f64>().expect(&format!("Can't parse arg #{} as f64", program_args[i]))),
|
&ValueType::F64 => RuntimeValue::F64(program_args[i].parse::<f64>().expect(&format!("Can't parse arg #{} as f64", program_args[i]))),
|
||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
interpreter::ExecutionParams::from(args)
|
interpreter::ExecutionParams::from(args)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Intialize deserialized module. It adds module into It expects 3 parameters:
|
// Intialize deserialized module. It adds module into It expects 3 parameters:
|
||||||
// - a name for the module
|
// - a name for the module
|
||||||
// - a module declaration
|
// - a module declaration
|
||||||
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
|
// - "main" module doesn't import native module(s) this is why we don't need to provide external native modules here
|
||||||
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
|
// This test shows how to implement native module https://github.com/NikVolf/parity-wasm/blob/master/src/interpreter/tests/basics.rs#L197
|
||||||
let module = program.add_module("main", module, None).expect("Failed to initialize module");
|
let module = program.add_module("main", module, None).expect("Failed to initialize module");
|
||||||
|
|
||||||
println!("Result: {:?}", module.execute_export(func_name, execution_params).expect(""));
|
println!("Result: {:?}", module.execute_export(func_name, execution_params).expect(""));
|
||||||
}
|
}
|
||||||
|
@ -3,24 +3,24 @@ extern crate parity_wasm;
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = env::args().collect::<Vec<_>>();
|
let args = env::args().collect::<Vec<_>>();
|
||||||
if args.len() != 3 {
|
if args.len() != 3 {
|
||||||
println!("Usage: {} in.wasm out.wasm", args[0]);
|
println!("Usage: {} in.wasm out.wasm", args[0]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let module = match parity_wasm::deserialize_file(&args[1])
|
let module = match parity_wasm::deserialize_file(&args[1])
|
||||||
.expect("Failed to load module")
|
.expect("Failed to load module")
|
||||||
.parse_names()
|
.parse_names()
|
||||||
{
|
{
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err((errors, m)) => {
|
Err((errors, m)) => {
|
||||||
for (index, error) in errors.into_iter() {
|
for (index, error) in errors.into_iter() {
|
||||||
println!("Custom section #{} parse error: {:?}", index, error);
|
println!("Custom section #{} parse error: {:?}", index, error);
|
||||||
}
|
}
|
||||||
m
|
m
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
parity_wasm::serialize_to_file(&args[2], module).expect("Failed to write module");
|
parity_wasm::serialize_to_file(&args[2], module).expect("Failed to write module");
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,15 @@ extern crate parity_wasm;
|
|||||||
extern crate binaryen;
|
extern crate binaryen;
|
||||||
|
|
||||||
fuzz_target!(|data: &[u8]| {
|
fuzz_target!(|data: &[u8]| {
|
||||||
let binaryen_module = binaryen::tools::translate_to_fuzz(data);
|
let binaryen_module = binaryen::tools::translate_to_fuzz(data);
|
||||||
|
|
||||||
// enable binaryen's validation if in doubt.
|
// enable binaryen's validation if in doubt.
|
||||||
// assert!(binaryen_module.is_valid());
|
// assert!(binaryen_module.is_valid());
|
||||||
|
|
||||||
let wasm = binaryen_module.write();
|
let wasm = binaryen_module.write();
|
||||||
|
|
||||||
let _module: parity_wasm::elements::Module = parity_wasm::deserialize_buffer(&wasm)
|
let _module: parity_wasm::elements::Module = parity_wasm::deserialize_buffer(&wasm)
|
||||||
.expect(
|
.expect(
|
||||||
"deserialize output of wasm-opt, indicating possible bug in deserializer",
|
"deserialize output of wasm-opt, indicating possible bug in deserializer",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
macro_rules! run_test {
|
macro_rules! run_test {
|
||||||
($label: expr, $test_name: ident, fail) => (
|
($label: expr, $test_name: ident, fail) => (
|
||||||
#[test]
|
#[test]
|
||||||
fn $test_name() {
|
fn $test_name() {
|
||||||
::run::failing_spec($label)
|
::run::failing_spec($label)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
($label: expr, $test_name: ident) => (
|
($label: expr, $test_name: ident) => (
|
||||||
#[test]
|
#[test]
|
||||||
fn $test_name() {
|
fn $test_name() {
|
||||||
::run::spec($label)
|
::run::spec($label)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
run_test!("address-offset-range.fail", wasm_address_offset_range_fail, fail);
|
run_test!("address-offset-range.fail", wasm_address_offset_range_fail, fail);
|
||||||
|
458
spec/src/run.rs
458
spec/src/run.rs
@ -10,276 +10,276 @@ use serde_json;
|
|||||||
use test;
|
use test;
|
||||||
use parity_wasm::{self, elements, builder};
|
use parity_wasm::{self, elements, builder};
|
||||||
use parity_wasm::interpreter::{
|
use parity_wasm::interpreter::{
|
||||||
RuntimeValue,
|
RuntimeValue,
|
||||||
ProgramInstance, ModuleInstance,
|
ProgramInstance, ModuleInstance,
|
||||||
ItemIndex, ExportEntryType,
|
ItemIndex, ExportEntryType,
|
||||||
Error as InterpreterError,
|
Error as InterpreterError,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn spec_test_module() -> elements::Module {
|
fn spec_test_module() -> elements::Module {
|
||||||
builder::module()
|
builder::module()
|
||||||
.function().signature().build().body().build().build()
|
.function().signature().build().body().build().build()
|
||||||
.function().signature().param().i32().build().body().build().build()
|
.function().signature().param().i32().build().body().build().build()
|
||||||
.function().signature().param().i64().build().body().build().build()
|
.function().signature().param().i64().build().body().build().build()
|
||||||
.function().signature().param().f32().build().body().build().build()
|
.function().signature().param().f32().build().body().build().build()
|
||||||
.function().signature().param().f64().build().body().build().build()
|
.function().signature().param().f64().build().body().build().build()
|
||||||
.function().signature().param().i32().param().f32().build().body().build().build()
|
.function().signature().param().i32().param().f32().build().body().build().build()
|
||||||
.function().signature().param().f64().param().f64().build().body().build().build()
|
.function().signature().param().f64().param().f64().build().body().build().build()
|
||||||
.global().value_type().i32().init_expr(elements::Opcode::I32Const(666)).build()
|
.global().value_type().i32().init_expr(elements::Opcode::I32Const(666)).build()
|
||||||
.with_table(elements::TableType::new(100, None))
|
.with_table(elements::TableType::new(100, None))
|
||||||
.memory().with_min(1).with_max(Some(2)).build()
|
.memory().with_min(1).with_max(Some(2)).build()
|
||||||
.export().field("print").internal().func(0).build()
|
.export().field("print").internal().func(0).build()
|
||||||
.export().field("print").internal().func(1).build()
|
.export().field("print").internal().func(1).build()
|
||||||
.export().field("print").internal().func(2).build()
|
.export().field("print").internal().func(2).build()
|
||||||
.export().field("print").internal().func(3).build()
|
.export().field("print").internal().func(3).build()
|
||||||
.export().field("print").internal().func(4).build()
|
.export().field("print").internal().func(4).build()
|
||||||
.export().field("print").internal().func(5).build()
|
.export().field("print").internal().func(5).build()
|
||||||
.export().field("print").internal().func(6).build()
|
.export().field("print").internal().func(6).build()
|
||||||
.export().field("global").internal().global(0).build()
|
.export().field("global").internal().global(0).build()
|
||||||
.export().field("table").internal().table(0).build()
|
.export().field("table").internal().table(0).build()
|
||||||
.export().field("memory").internal().memory(0).build()
|
.export().field("memory").internal().memory(0).build()
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_module(base_dir: &str, path: &str, name: &Option<String>, program: &ProgramInstance) -> Arc<ModuleInstance> {
|
fn load_module(base_dir: &str, path: &str, name: &Option<String>, program: &ProgramInstance) -> Arc<ModuleInstance> {
|
||||||
let module = try_deserialize(base_dir, path).expect(&format!("Wasm file {} failed to load", path));
|
let module = try_deserialize(base_dir, path).expect(&format!("Wasm file {} failed to load", path));
|
||||||
|
|
||||||
program.add_module("spectest", spec_test_module(), None).expect("Failed adding 'spectest' module");
|
program.add_module("spectest", spec_test_module(), None).expect("Failed adding 'spectest' module");
|
||||||
|
|
||||||
let module_name = name.as_ref().map(|s| s.as_ref()).unwrap_or("wasm_test").trim_left_matches('$');
|
let module_name = name.as_ref().map(|s| s.as_ref()).unwrap_or("wasm_test").trim_left_matches('$');
|
||||||
let module_instance = program.add_module(module_name, module, None).expect(&format!("Failed adding {} module", module_name));
|
let module_instance = program.add_module(module_name, module, None).expect(&format!("Failed adding {} module", module_name));
|
||||||
module_instance
|
module_instance
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_deserialize(base_dir: &str, module_path: &str) -> Result<elements::Module, elements::Error> {
|
fn try_deserialize(base_dir: &str, module_path: &str) -> Result<elements::Module, elements::Error> {
|
||||||
let mut wasm_path = PathBuf::from(base_dir.clone());
|
let mut wasm_path = PathBuf::from(base_dir.clone());
|
||||||
wasm_path.push(module_path);
|
wasm_path.push(module_path);
|
||||||
parity_wasm::deserialize_file(&wasm_path)
|
parity_wasm::deserialize_file(&wasm_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_load(base_dir: &str, module_path: &str) -> Result<(), InterpreterError> {
|
fn try_load(base_dir: &str, module_path: &str) -> Result<(), InterpreterError> {
|
||||||
let module = try_deserialize(base_dir, module_path).map_err(|e| parity_wasm::interpreter::Error::Program(format!("{:?}", e)))?;
|
let module = try_deserialize(base_dir, module_path).map_err(|e| parity_wasm::interpreter::Error::Program(format!("{:?}", e)))?;
|
||||||
let program = ProgramInstance::new();
|
let program = ProgramInstance::new();
|
||||||
program.add_module("try_load", module, None).map(|_| ())
|
program.add_module("try_load", module, None).map(|_| ())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runtime_value(test_val: &test::RuntimeValue) -> parity_wasm::RuntimeValue {
|
fn runtime_value(test_val: &test::RuntimeValue) -> parity_wasm::RuntimeValue {
|
||||||
match test_val.value_type.as_ref() {
|
match test_val.value_type.as_ref() {
|
||||||
"i32" => {
|
"i32" => {
|
||||||
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
||||||
parity_wasm::RuntimeValue::I32(unsigned as i32)
|
parity_wasm::RuntimeValue::I32(unsigned as i32)
|
||||||
},
|
},
|
||||||
"i64" => {
|
"i64" => {
|
||||||
let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
|
let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
|
||||||
parity_wasm::RuntimeValue::I64(unsigned as i64)
|
parity_wasm::RuntimeValue::I64(unsigned as i64)
|
||||||
},
|
},
|
||||||
"f32" => {
|
"f32" => {
|
||||||
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
let unsigned: u32 = test_val.value.parse().expect("Literal parse error");
|
||||||
parity_wasm::RuntimeValue::decode_f32(unsigned)
|
parity_wasm::RuntimeValue::decode_f32(unsigned)
|
||||||
},
|
},
|
||||||
"f64" => {
|
"f64" => {
|
||||||
let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
|
let unsigned: u64 = test_val.value.parse().expect("Literal parse error");
|
||||||
parity_wasm::RuntimeValue::decode_f64(unsigned)
|
parity_wasm::RuntimeValue::decode_f64(unsigned)
|
||||||
},
|
},
|
||||||
_ => panic!("Unknwon runtime value type"),
|
_ => panic!("Unknwon runtime value type"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn runtime_values(test_vals: &[test::RuntimeValue]) -> Vec<parity_wasm::RuntimeValue> {
|
fn runtime_values(test_vals: &[test::RuntimeValue]) -> Vec<parity_wasm::RuntimeValue> {
|
||||||
test_vals.iter().map(runtime_value).collect::<Vec<parity_wasm::RuntimeValue>>()
|
test_vals.iter().map(runtime_value).collect::<Vec<parity_wasm::RuntimeValue>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_action(program: &ProgramInstance, action: &test::Action)
|
fn run_action(program: &ProgramInstance, action: &test::Action)
|
||||||
-> Result<Option<parity_wasm::RuntimeValue>, InterpreterError>
|
-> Result<Option<parity_wasm::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
match *action {
|
match *action {
|
||||||
test::Action::Invoke { ref module, ref field, ref args } => {
|
test::Action::Invoke { ref module, ref field, ref args } => {
|
||||||
let module = module.clone().unwrap_or("wasm_test".into());
|
let module = module.clone().unwrap_or("wasm_test".into());
|
||||||
let module = module.trim_left_matches('$');
|
let module = module.trim_left_matches('$');
|
||||||
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
|
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
|
||||||
module.execute_export(&jstring_to_rstring(field), runtime_values(args).into())
|
module.execute_export(&jstring_to_rstring(field), runtime_values(args).into())
|
||||||
},
|
},
|
||||||
test::Action::Get { ref module, ref field, .. } => {
|
test::Action::Get { ref module, ref field, .. } => {
|
||||||
let module = module.clone().unwrap_or("wasm_test".into());
|
let module = module.clone().unwrap_or("wasm_test".into());
|
||||||
let module = module.trim_left_matches('$');
|
let module = module.trim_left_matches('$');
|
||||||
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
|
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
|
||||||
let field = jstring_to_rstring(&field);
|
let field = jstring_to_rstring(&field);
|
||||||
|
|
||||||
module.export_entry(field.as_ref(), &ExportEntryType::Any)
|
module.export_entry(field.as_ref(), &ExportEntryType::Any)
|
||||||
.and_then(|i| match i {
|
.and_then(|i| match i {
|
||||||
elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)),
|
elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)),
|
||||||
_ => Err(InterpreterError::Global(format!("Expected to have exported global with name {}", field))),
|
_ => Err(InterpreterError::Global(format!("Expected to have exported global with name {}", field))),
|
||||||
})
|
})
|
||||||
.and_then(|g| module.global(g, None, None).map(|g| Some(g.get())))
|
.and_then(|g| module.global(g, None, None).map(|g| Some(g.get())))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FixtureParams {
|
pub struct FixtureParams {
|
||||||
failing: bool,
|
failing: bool,
|
||||||
json: String,
|
json: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_wast2wasm(name: &str) -> FixtureParams {
|
pub fn run_wast2wasm(name: &str) -> FixtureParams {
|
||||||
let outdir = env::var("OUT_DIR").unwrap();
|
let outdir = env::var("OUT_DIR").unwrap();
|
||||||
|
|
||||||
let mut wast2wasm_path = PathBuf::from(outdir.clone());
|
let mut wast2wasm_path = PathBuf::from(outdir.clone());
|
||||||
wast2wasm_path.push("bin");
|
wast2wasm_path.push("bin");
|
||||||
wast2wasm_path.push("wast2wasm");
|
wast2wasm_path.push("wast2wasm");
|
||||||
|
|
||||||
let mut json_spec_path = PathBuf::from(outdir.clone());
|
let mut json_spec_path = PathBuf::from(outdir.clone());
|
||||||
json_spec_path.push(&format!("{}.json", name));
|
json_spec_path.push(&format!("{}.json", name));
|
||||||
|
|
||||||
let wast2wasm_output = Command::new(wast2wasm_path)
|
let wast2wasm_output = Command::new(wast2wasm_path)
|
||||||
.arg("--spec")
|
.arg("--spec")
|
||||||
.arg("-o")
|
.arg("-o")
|
||||||
.arg(&json_spec_path)
|
.arg(&json_spec_path)
|
||||||
.arg(&format!("./wabt/third_party/testsuite/{}.wast", name))
|
.arg(&format!("./wabt/third_party/testsuite/{}.wast", name))
|
||||||
.output()
|
.output()
|
||||||
.expect("Failed to execute process");
|
.expect("Failed to execute process");
|
||||||
|
|
||||||
FixtureParams {
|
FixtureParams {
|
||||||
json: json_spec_path.to_str().unwrap().to_owned(),
|
json: json_spec_path.to_str().unwrap().to_owned(),
|
||||||
failing: {
|
failing: {
|
||||||
if !wast2wasm_output.status.success() {
|
if !wast2wasm_output.status.success() {
|
||||||
println!("wasm2wast error code: {}", wast2wasm_output.status);
|
println!("wasm2wast error code: {}", wast2wasm_output.status);
|
||||||
println!("wasm2wast stdout: {}", String::from_utf8_lossy(&wast2wasm_output.stdout));
|
println!("wasm2wast stdout: {}", String::from_utf8_lossy(&wast2wasm_output.stdout));
|
||||||
println!("wasm2wast stderr: {}", String::from_utf8_lossy(&wast2wasm_output.stderr));
|
println!("wasm2wast stderr: {}", String::from_utf8_lossy(&wast2wasm_output.stderr));
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn failing_spec(name: &str) {
|
pub fn failing_spec(name: &str) {
|
||||||
let fixture = run_wast2wasm(name);
|
let fixture = run_wast2wasm(name);
|
||||||
if !fixture.failing {
|
if !fixture.failing {
|
||||||
panic!("wasm2wast expected to fail, but terminated normally");
|
panic!("wasm2wast expected to fail, but terminated normally");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spec(name: &str) {
|
pub fn spec(name: &str) {
|
||||||
let outdir = env::var("OUT_DIR").unwrap();
|
let outdir = env::var("OUT_DIR").unwrap();
|
||||||
|
|
||||||
let fixture = run_wast2wasm(name);
|
let fixture = run_wast2wasm(name);
|
||||||
if fixture.failing {
|
if fixture.failing {
|
||||||
panic!("wasm2wast terminated abnormally, expected to success");
|
panic!("wasm2wast terminated abnormally, expected to success");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut f = File::open(&fixture.json)
|
let mut f = File::open(&fixture.json)
|
||||||
.expect(&format!("Failed to load json file {}", &fixture.json));
|
.expect(&format!("Failed to load json file {}", &fixture.json));
|
||||||
let spec: test::Spec = serde_json::from_reader(&mut f).expect("Failed to deserialize JSON file");
|
let spec: test::Spec = serde_json::from_reader(&mut f).expect("Failed to deserialize JSON file");
|
||||||
|
|
||||||
let program = ProgramInstance::new();
|
let program = ProgramInstance::new();
|
||||||
let mut last_module = None;
|
let mut last_module = None;
|
||||||
for command in &spec.commands {
|
for command in &spec.commands {
|
||||||
println!("command {:?}", command);
|
println!("command {:?}", command);
|
||||||
match command {
|
match command {
|
||||||
&test::Command::Module { ref name, ref filename, .. } => {
|
&test::Command::Module { ref name, ref filename, .. } => {
|
||||||
last_module = Some(load_module(&outdir, &filename, &name, &program));
|
last_module = Some(load_module(&outdir, &filename, &name, &program));
|
||||||
},
|
},
|
||||||
&test::Command::AssertReturn { line, ref action, ref expected } => {
|
&test::Command::AssertReturn { line, ref action, ref expected } => {
|
||||||
let result = run_action(&program, action);
|
let result = run_action(&program, action);
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
let spec_expected = runtime_values(expected);
|
let spec_expected = runtime_values(expected);
|
||||||
let actual_result = result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>();
|
let actual_result = result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>();
|
||||||
for (actual_result, spec_expected) in actual_result.iter().zip(spec_expected.iter()) {
|
for (actual_result, spec_expected) in actual_result.iter().zip(spec_expected.iter()) {
|
||||||
assert_eq!(actual_result.variable_type(), spec_expected.variable_type());
|
assert_eq!(actual_result.variable_type(), spec_expected.variable_type());
|
||||||
// f32::NAN != f32::NAN
|
// f32::NAN != f32::NAN
|
||||||
match spec_expected {
|
match spec_expected {
|
||||||
&RuntimeValue::F32(val) if val.is_nan() => match actual_result {
|
&RuntimeValue::F32(val) if val.is_nan() => match actual_result {
|
||||||
&RuntimeValue::F32(val) => assert!(val.is_nan()),
|
&RuntimeValue::F32(val) => assert!(val.is_nan()),
|
||||||
_ => unreachable!(), // checked above that types are same
|
_ => unreachable!(), // checked above that types are same
|
||||||
},
|
},
|
||||||
&RuntimeValue::F64(val) if val.is_nan() => match actual_result {
|
&RuntimeValue::F64(val) if val.is_nan() => match actual_result {
|
||||||
&RuntimeValue::F64(val) => assert!(val.is_nan()),
|
&RuntimeValue::F64(val) => assert!(val.is_nan()),
|
||||||
_ => unreachable!(), // checked above that types are same
|
_ => unreachable!(), // checked above that types are same
|
||||||
},
|
},
|
||||||
spec_expected @ _ => assert_eq!(actual_result, spec_expected),
|
spec_expected @ _ => assert_eq!(actual_result, spec_expected),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("assert_return at line {} - success", line);
|
println!("assert_return at line {} - success", line);
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("Expected action to return value, got error: {:?}", e);
|
panic!("Expected action to return value, got error: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&test::Command::AssertReturnCanonicalNan { line, ref action } | &test::Command::AssertReturnArithmeticNan { line, ref action } => {
|
&test::Command::AssertReturnCanonicalNan { line, ref action } | &test::Command::AssertReturnArithmeticNan { line, ref action } => {
|
||||||
let result = run_action(&program, action);
|
let result = run_action(&program, action);
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
for actual_result in result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>() {
|
for actual_result in result.into_iter().collect::<Vec<parity_wasm::RuntimeValue>>() {
|
||||||
match actual_result {
|
match actual_result {
|
||||||
RuntimeValue::F32(val) => if !val.is_nan() { panic!("Expected nan value, got {:?}", val) },
|
RuntimeValue::F32(val) => if !val.is_nan() { panic!("Expected nan value, got {:?}", val) },
|
||||||
RuntimeValue::F64(val) => if !val.is_nan() { panic!("Expected nan value, got {:?}", val) },
|
RuntimeValue::F64(val) => if !val.is_nan() { panic!("Expected nan value, got {:?}", val) },
|
||||||
val @ _ => panic!("Expected action to return float value, got {:?}", val),
|
val @ _ => panic!("Expected action to return float value, got {:?}", val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("assert_return_nan at line {} - success", line);
|
println!("assert_return_nan at line {} - success", line);
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("Expected action to return value, got error: {:?}", e);
|
panic!("Expected action to return value, got error: {:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&test::Command::AssertExhaustion { line, ref action, .. } => {
|
&test::Command::AssertExhaustion { line, ref action, .. } => {
|
||||||
let result = run_action(&program, action);
|
let result = run_action(&program, action);
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => panic!("Expected exhaustion, got result: {:?}", result),
|
Ok(result) => panic!("Expected exhaustion, got result: {:?}", result),
|
||||||
Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e),
|
Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&test::Command::AssertTrap { line, ref action, .. } => {
|
&test::Command::AssertTrap { line, ref action, .. } => {
|
||||||
let result = run_action(&program, action);
|
let result = run_action(&program, action);
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
panic!("Expected action to result in a trap, got result: {:?}", result);
|
panic!("Expected action to result in a trap, got result: {:?}", result);
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("assert_trap at line {} - success ({:?})", line, e);
|
println!("assert_trap at line {} - success ({:?})", line, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&test::Command::AssertInvalid { line, ref filename, .. }
|
&test::Command::AssertInvalid { line, ref filename, .. }
|
||||||
| &test::Command::AssertMalformed { line, ref filename, .. }
|
| &test::Command::AssertMalformed { line, ref filename, .. }
|
||||||
| &test::Command::AssertUnlinkable { line, ref filename, .. }
|
| &test::Command::AssertUnlinkable { line, ref filename, .. }
|
||||||
=> {
|
=> {
|
||||||
let module_load = try_load(&outdir, filename);
|
let module_load = try_load(&outdir, filename);
|
||||||
match module_load {
|
match module_load {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
panic!("Expected invalid module definition, got some module!")
|
panic!("Expected invalid module definition, got some module!")
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("assert_invalid at line {} - success ({:?})", line, e)
|
println!("assert_invalid at line {} - success ({:?})", line, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&test::Command::AssertUninstantiable { line, ref filename, .. } => {
|
&test::Command::AssertUninstantiable { line, ref filename, .. } => {
|
||||||
match try_load(&outdir, &filename) {
|
match try_load(&outdir, &filename) {
|
||||||
Ok(_) => panic!("Expected error running start function at line {}", line),
|
Ok(_) => panic!("Expected error running start function at line {}", line),
|
||||||
Err(e) => println!("assert_uninstantiable - success ({:?})", e),
|
Err(e) => println!("assert_uninstantiable - success ({:?})", e),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&test::Command::Register { ref name, ref as_name, .. } => {
|
&test::Command::Register { ref name, ref as_name, .. } => {
|
||||||
match name {
|
match name {
|
||||||
&Some(ref name) => assert_eq!(name.trim_left_matches('$'), as_name), // we have already registered this module without $ prefix
|
&Some(ref name) => assert_eq!(name.trim_left_matches('$'), as_name), // we have already registered this module without $ prefix
|
||||||
&None => program.insert_loaded_module(as_name, last_module.take().expect("Last module must be set for this command")).map(|_| ()).unwrap(),
|
&None => program.insert_loaded_module(as_name, last_module.take().expect("Last module must be set for this command")).map(|_| ()).unwrap(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
&test::Command::Action { line, ref action } => {
|
&test::Command::Action { line, ref action } => {
|
||||||
match run_action(&program, action) {
|
match run_action(&program, action) {
|
||||||
Ok(_) => { },
|
Ok(_) => { },
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
panic!("Failed to invoke action at line {}: {:?}", line, e)
|
panic!("Failed to invoke action at line {}: {:?}", line, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert json string to correct rust UTF8 string.
|
// Convert json string to correct rust UTF8 string.
|
||||||
@ -287,7 +287,7 @@ pub fn spec(name: &str) {
|
|||||||
// It is incorrect. Correct BOM representation in json is "\uFEFF" => we need to do a double utf8-parse here.
|
// It is incorrect. Correct BOM representation in json is "\uFEFF" => we need to do a double utf8-parse here.
|
||||||
// This conversion is incorrect in general case (casting char to u8)!!!
|
// This conversion is incorrect in general case (casting char to u8)!!!
|
||||||
fn jstring_to_rstring(jstring: &str) -> String {
|
fn jstring_to_rstring(jstring: &str) -> String {
|
||||||
let jstring_chars: Vec<u8> = jstring.chars().map(|c| c as u8).collect();
|
let jstring_chars: Vec<u8> = jstring.chars().map(|c| c as u8).collect();
|
||||||
let rstring = String::from_utf8(jstring_chars).unwrap();
|
let rstring = String::from_utf8(jstring_chars).unwrap();
|
||||||
rstring
|
rstring
|
||||||
}
|
}
|
||||||
|
170
spec/src/test.rs
170
spec/src/test.rs
@ -2,103 +2,103 @@
|
|||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct RuntimeValue {
|
pub struct RuntimeValue {
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub value_type: String,
|
pub value_type: String,
|
||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
#[serde(rename = "invoke")]
|
#[serde(rename = "invoke")]
|
||||||
Invoke {
|
Invoke {
|
||||||
module: Option<String>,
|
module: Option<String>,
|
||||||
field: String,
|
field: String,
|
||||||
args: Vec<RuntimeValue>,
|
args: Vec<RuntimeValue>,
|
||||||
},
|
},
|
||||||
#[serde(rename = "get")]
|
#[serde(rename = "get")]
|
||||||
Get {
|
Get {
|
||||||
module: Option<String>,
|
module: Option<String>,
|
||||||
field: String,
|
field: String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
#[serde(rename = "module")]
|
#[serde(rename = "module")]
|
||||||
Module {
|
Module {
|
||||||
line: u64,
|
line: u64,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
filename: String
|
filename: String
|
||||||
},
|
},
|
||||||
#[serde(rename = "assert_return")]
|
#[serde(rename = "assert_return")]
|
||||||
AssertReturn {
|
AssertReturn {
|
||||||
line: u64,
|
line: u64,
|
||||||
action: Action,
|
action: Action,
|
||||||
expected: Vec<RuntimeValue>,
|
expected: Vec<RuntimeValue>,
|
||||||
},
|
},
|
||||||
#[serde(rename = "assert_return_canonical_nan")]
|
#[serde(rename = "assert_return_canonical_nan")]
|
||||||
AssertReturnCanonicalNan {
|
AssertReturnCanonicalNan {
|
||||||
line: u64,
|
line: u64,
|
||||||
action: Action,
|
action: Action,
|
||||||
},
|
},
|
||||||
#[serde(rename = "assert_return_arithmetic_nan")]
|
#[serde(rename = "assert_return_arithmetic_nan")]
|
||||||
AssertReturnArithmeticNan {
|
AssertReturnArithmeticNan {
|
||||||
line: u64,
|
line: u64,
|
||||||
action: Action,
|
action: Action,
|
||||||
},
|
},
|
||||||
#[serde(rename = "assert_trap")]
|
#[serde(rename = "assert_trap")]
|
||||||
AssertTrap {
|
AssertTrap {
|
||||||
line: u64,
|
line: u64,
|
||||||
action: Action,
|
action: Action,
|
||||||
text: String,
|
text: String,
|
||||||
},
|
},
|
||||||
#[serde(rename = "assert_invalid")]
|
#[serde(rename = "assert_invalid")]
|
||||||
AssertInvalid {
|
AssertInvalid {
|
||||||
line: u64,
|
line: u64,
|
||||||
filename: String,
|
filename: String,
|
||||||
text: String,
|
text: String,
|
||||||
},
|
},
|
||||||
#[serde(rename = "assert_malformed")]
|
#[serde(rename = "assert_malformed")]
|
||||||
AssertMalformed {
|
AssertMalformed {
|
||||||
line: u64,
|
line: u64,
|
||||||
filename: String,
|
filename: String,
|
||||||
text: String,
|
text: String,
|
||||||
},
|
},
|
||||||
#[serde(rename = "assert_uninstantiable")]
|
#[serde(rename = "assert_uninstantiable")]
|
||||||
AssertUninstantiable {
|
AssertUninstantiable {
|
||||||
line: u64,
|
line: u64,
|
||||||
filename: String,
|
filename: String,
|
||||||
text: String,
|
text: String,
|
||||||
},
|
},
|
||||||
#[serde(rename = "assert_exhaustion")]
|
#[serde(rename = "assert_exhaustion")]
|
||||||
AssertExhaustion {
|
AssertExhaustion {
|
||||||
line: u64,
|
line: u64,
|
||||||
action: Action,
|
action: Action,
|
||||||
},
|
},
|
||||||
#[serde(rename = "assert_unlinkable")]
|
#[serde(rename = "assert_unlinkable")]
|
||||||
AssertUnlinkable {
|
AssertUnlinkable {
|
||||||
line: u64,
|
line: u64,
|
||||||
filename: String,
|
filename: String,
|
||||||
text: String,
|
text: String,
|
||||||
},
|
},
|
||||||
#[serde(rename = "register")]
|
#[serde(rename = "register")]
|
||||||
Register {
|
Register {
|
||||||
line: u64,
|
line: u64,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
#[serde(rename = "as")]
|
#[serde(rename = "as")]
|
||||||
as_name: String,
|
as_name: String,
|
||||||
},
|
},
|
||||||
#[serde(rename = "action")]
|
#[serde(rename = "action")]
|
||||||
Action {
|
Action {
|
||||||
line: u64,
|
line: u64,
|
||||||
action: Action,
|
action: Action,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct Spec {
|
pub struct Spec {
|
||||||
pub source_filename: String,
|
pub source_filename: String,
|
||||||
pub commands: Vec<Command>,
|
pub commands: Vec<Command>,
|
||||||
}
|
}
|
@ -4,170 +4,170 @@ use super::misc::{ValueTypeBuilder, ValueTypesBuilder, OptionalValueTypeBuilder}
|
|||||||
|
|
||||||
/// Signature template description
|
/// Signature template description
|
||||||
pub enum Signature {
|
pub enum Signature {
|
||||||
TypeReference(u32),
|
TypeReference(u32),
|
||||||
Inline(elements::FunctionType),
|
Inline(elements::FunctionType),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Signature builder
|
/// Signature builder
|
||||||
pub struct SignatureBuilder<F=Identity> {
|
pub struct SignatureBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
signature: elements::FunctionType,
|
signature: elements::FunctionType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignatureBuilder {
|
impl SignatureBuilder {
|
||||||
/// New signature builder
|
/// New signature builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SignatureBuilder::with_callback(Identity)
|
SignatureBuilder::with_callback(Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> SignatureBuilder<F> where F: Invoke<elements::FunctionType> {
|
impl<F> SignatureBuilder<F> where F: Invoke<elements::FunctionType> {
|
||||||
/// New builder with callback function specified
|
/// New builder with callback function specified
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
SignatureBuilder {
|
SignatureBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
signature: elements::FunctionType::default(),
|
signature: elements::FunctionType::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add argument to signature builder
|
/// Add argument to signature builder
|
||||||
pub fn with_param(mut self, value_type: elements::ValueType) -> Self {
|
pub fn with_param(mut self, value_type: elements::ValueType) -> Self {
|
||||||
self.signature.params_mut().push(value_type);
|
self.signature.params_mut().push(value_type);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add multiple arguments to signature builder
|
/// Add multiple arguments to signature builder
|
||||||
pub fn with_params(mut self, value_types: Vec<elements::ValueType>) -> Self {
|
pub fn with_params(mut self, value_types: Vec<elements::ValueType>) -> Self {
|
||||||
self.signature.params_mut().extend(value_types);
|
self.signature.params_mut().extend(value_types);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Override signature return type
|
/// Override signature return type
|
||||||
pub fn with_return_type(mut self, return_type: Option<elements::ValueType>) -> Self {
|
pub fn with_return_type(mut self, return_type: Option<elements::ValueType>) -> Self {
|
||||||
*self.signature.return_type_mut() = return_type;
|
*self.signature.return_type_mut() = return_type;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start build new argument
|
/// Start build new argument
|
||||||
pub fn param(self) -> ValueTypeBuilder<Self> {
|
pub fn param(self) -> ValueTypeBuilder<Self> {
|
||||||
ValueTypeBuilder::with_callback(self)
|
ValueTypeBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start build multiple arguments
|
/// Start build multiple arguments
|
||||||
pub fn params(self) -> ValueTypesBuilder<Self> {
|
pub fn params(self) -> ValueTypesBuilder<Self> {
|
||||||
ValueTypesBuilder::with_callback(self)
|
ValueTypesBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start building return type
|
/// Start building return type
|
||||||
pub fn return_type(self) -> OptionalValueTypeBuilder<Self> {
|
pub fn return_type(self) -> OptionalValueTypeBuilder<Self> {
|
||||||
OptionalValueTypeBuilder::with_callback(self)
|
OptionalValueTypeBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish current builder
|
/// Finish current builder
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(self.signature)
|
self.callback.invoke(self.signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish current builder returning intermediate `Signature` struct
|
/// Finish current builder returning intermediate `Signature` struct
|
||||||
pub fn build_sig(self) -> Signature {
|
pub fn build_sig(self) -> Signature {
|
||||||
Signature::Inline(self.signature)
|
Signature::Inline(self.signature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<Vec<elements::ValueType>> for SignatureBuilder<F>
|
impl<F> Invoke<Vec<elements::ValueType>> for SignatureBuilder<F>
|
||||||
where F: Invoke<elements::FunctionType>
|
where F: Invoke<elements::FunctionType>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, args: Vec<elements::ValueType>) -> Self {
|
fn invoke(self, args: Vec<elements::ValueType>) -> Self {
|
||||||
self.with_params(args)
|
self.with_params(args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<Option<elements::ValueType>> for SignatureBuilder<F>
|
impl<F> Invoke<Option<elements::ValueType>> for SignatureBuilder<F>
|
||||||
where F: Invoke<elements::FunctionType>
|
where F: Invoke<elements::FunctionType>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, arg: Option<elements::ValueType>) -> Self {
|
fn invoke(self, arg: Option<elements::ValueType>) -> Self {
|
||||||
self.with_return_type(arg)
|
self.with_return_type(arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::ValueType> for SignatureBuilder<F>
|
impl<F> Invoke<elements::ValueType> for SignatureBuilder<F>
|
||||||
where F: Invoke<elements::FunctionType>
|
where F: Invoke<elements::FunctionType>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, arg: elements::ValueType) -> Self {
|
fn invoke(self, arg: elements::ValueType) -> Self {
|
||||||
self.with_param(arg)
|
self.with_param(arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type (signature) reference builder (for function/import/indirect call)
|
/// Type (signature) reference builder (for function/import/indirect call)
|
||||||
pub struct TypeRefBuilder<F=Identity> {
|
pub struct TypeRefBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
type_ref: u32,
|
type_ref: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> TypeRefBuilder<F> where F: Invoke<u32> {
|
impl<F> TypeRefBuilder<F> where F: Invoke<u32> {
|
||||||
/// New builder chained with specified callback
|
/// New builder chained with specified callback
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
TypeRefBuilder {
|
TypeRefBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
type_ref: 0
|
type_ref: 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set/override of type reference
|
/// Set/override of type reference
|
||||||
pub fn val(mut self, val: u32) -> Self {
|
pub fn val(mut self, val: u32) -> Self {
|
||||||
self.type_ref = val;
|
self.type_ref = val;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish current builder
|
/// Finish current builder
|
||||||
pub fn build(self) -> F::Result { self.callback.invoke(self.type_ref) }
|
pub fn build(self) -> F::Result { self.callback.invoke(self.type_ref) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiple signatures builder
|
/// Multiple signatures builder
|
||||||
pub struct SignaturesBuilder<F=Identity> {
|
pub struct SignaturesBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
section: Vec<Signature>,
|
section: Vec<Signature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignaturesBuilder {
|
impl SignaturesBuilder {
|
||||||
/// New empty functions section builder
|
/// New empty functions section builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
SignaturesBuilder::with_callback(Identity)
|
SignaturesBuilder::with_callback(Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> SignaturesBuilder<F> {
|
impl<F> SignaturesBuilder<F> {
|
||||||
/// New builder chained with specified callback
|
/// New builder chained with specified callback
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
SignaturesBuilder {
|
SignaturesBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
section: Vec::new(),
|
section: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push new signature into the builder output
|
/// Push new signature into the builder output
|
||||||
pub fn with_signature(mut self, signature: Signature) -> Self {
|
pub fn with_signature(mut self, signature: Signature) -> Self {
|
||||||
self.section.push(signature);
|
self.section.push(signature);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start building new signature with `TypeRefBuilder`
|
/// Start building new signature with `TypeRefBuilder`
|
||||||
pub fn type_ref(self) -> TypeRefBuilder<Self> {
|
pub fn type_ref(self) -> TypeRefBuilder<Self> {
|
||||||
TypeRefBuilder::with_callback(self)
|
TypeRefBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> {
|
impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> {
|
||||||
/// Start building new signature with dedicated builder
|
/// Start building new signature with dedicated builder
|
||||||
pub fn signature(self) -> SignatureBuilder<Self> {
|
pub fn signature(self) -> SignatureBuilder<Self> {
|
||||||
SignatureBuilder::with_callback(self)
|
SignatureBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::FunctionType> for SignaturesBuilder<F> {
|
impl<F> Invoke<elements::FunctionType> for SignaturesBuilder<F> {
|
||||||
@ -175,7 +175,7 @@ impl<F> Invoke<elements::FunctionType> for SignaturesBuilder<F> {
|
|||||||
|
|
||||||
fn invoke(self, signature: elements::FunctionType) -> Self {
|
fn invoke(self, signature: elements::FunctionType) -> Self {
|
||||||
self.with_signature(Signature::Inline(signature))
|
self.with_signature(Signature::Inline(signature))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<u32> for SignaturesBuilder<F> {
|
impl<F> Invoke<u32> for SignaturesBuilder<F> {
|
||||||
@ -183,150 +183,150 @@ impl<F> Invoke<u32> for SignaturesBuilder<F> {
|
|||||||
|
|
||||||
fn invoke(self, type_ref: u32) -> Self {
|
fn invoke(self, type_ref: u32) -> Self {
|
||||||
self.with_signature(Signature::TypeReference(type_ref))
|
self.with_signature(Signature::TypeReference(type_ref))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> SignaturesBuilder<F> where F: Invoke<elements::FunctionSection> {
|
impl<F> SignaturesBuilder<F> where F: Invoke<elements::FunctionSection> {
|
||||||
|
|
||||||
/// Finalize builder spawning element
|
/// Finalize builder spawning element
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
let mut result = elements::FunctionSection::default();
|
let mut result = elements::FunctionSection::default();
|
||||||
for f in self.section.into_iter() {
|
for f in self.section.into_iter() {
|
||||||
if let Signature::TypeReference(type_ref) = f {
|
if let Signature::TypeReference(type_ref) = f {
|
||||||
result.entries_mut().push(elements::Func::new(type_ref));
|
result.entries_mut().push(elements::Func::new(type_ref));
|
||||||
} else {
|
} else {
|
||||||
unreachable!(); // never possible with current generics impl-s
|
unreachable!(); // never possible with current generics impl-s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.callback.invoke(result)
|
self.callback.invoke(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Signature bindings
|
/// Signature bindings
|
||||||
pub type SignatureBindings = Vec<Signature>;
|
pub type SignatureBindings = Vec<Signature>;
|
||||||
|
|
||||||
impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> {
|
impl<F> SignaturesBuilder<F> where F: Invoke<SignatureBindings> {
|
||||||
/// Bind signature list
|
/// Bind signature list
|
||||||
pub fn bind(self) -> F::Result {
|
pub fn bind(self) -> F::Result {
|
||||||
self.callback.invoke(self.section)
|
self.callback.invoke(self.section)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function body (code) builder
|
/// Function body (code) builder
|
||||||
pub struct FuncBodyBuilder<F=Identity> {
|
pub struct FuncBodyBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
body: elements::FuncBody,
|
body: elements::FuncBody,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> FuncBodyBuilder<F> {
|
impl<F> FuncBodyBuilder<F> {
|
||||||
/// New body (code) builder given the chain callback
|
/// New body (code) builder given the chain callback
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
FuncBodyBuilder {
|
FuncBodyBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
body: elements::FuncBody::new(Vec::new(), elements::Opcodes::empty()),
|
body: elements::FuncBody::new(Vec::new(), elements::Opcodes::empty()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> FuncBodyBuilder<F> where F: Invoke<elements::FuncBody> {
|
impl<F> FuncBodyBuilder<F> where F: Invoke<elements::FuncBody> {
|
||||||
/// Set/override entirely with FuncBody struct
|
/// Set/override entirely with FuncBody struct
|
||||||
pub fn with_func(mut self, func: elements::FuncBody) -> Self {
|
pub fn with_func(mut self, func: elements::FuncBody) -> Self {
|
||||||
self.body = func;
|
self.body = func;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extend function local list with new entries
|
/// Extend function local list with new entries
|
||||||
pub fn with_locals(mut self, locals: Vec<elements::Local>) -> Self {
|
pub fn with_locals(mut self, locals: Vec<elements::Local>) -> Self {
|
||||||
self.body.locals_mut().extend(locals);
|
self.body.locals_mut().extend(locals);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set code of the function
|
/// Set code of the function
|
||||||
pub fn with_opcodes(mut self, opcodes: elements::Opcodes) -> Self {
|
pub fn with_opcodes(mut self, opcodes: elements::Opcodes) -> Self {
|
||||||
*self.body.code_mut() = opcodes;
|
*self.body.code_mut() = opcodes;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish current builder spawning resulting struct
|
/// Finish current builder spawning resulting struct
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(self.body)
|
self.callback.invoke(self.body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function definition (extended structure to specify function entirely, incl. signature, mainness and code)
|
/// Function definition (extended structure to specify function entirely, incl. signature, mainness and code)
|
||||||
pub struct FunctionDefinition {
|
pub struct FunctionDefinition {
|
||||||
/// Is this function is start function
|
/// Is this function is start function
|
||||||
pub is_main: bool,
|
pub is_main: bool,
|
||||||
/// Signature description
|
/// Signature description
|
||||||
pub signature: Signature,
|
pub signature: Signature,
|
||||||
/// Body (code) of the function
|
/// Body (code) of the function
|
||||||
pub code: elements::FuncBody,
|
pub code: elements::FuncBody,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FunctionDefinition {
|
impl Default for FunctionDefinition {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
FunctionDefinition {
|
FunctionDefinition {
|
||||||
is_main: false,
|
is_main: false,
|
||||||
signature: Signature::TypeReference(0),
|
signature: Signature::TypeReference(0),
|
||||||
code: elements::FuncBody::empty(),
|
code: elements::FuncBody::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function definition builder
|
/// Function definition builder
|
||||||
pub struct FunctionBuilder<F=Identity> {
|
pub struct FunctionBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
func: FunctionDefinition,
|
func: FunctionDefinition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionBuilder {
|
impl FunctionBuilder {
|
||||||
/// New function builder
|
/// New function builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
FunctionBuilder::with_callback(Identity)
|
FunctionBuilder::with_callback(Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
impl<F> FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
||||||
/// New function builder with chained callback
|
/// New function builder with chained callback
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
FunctionBuilder {
|
FunctionBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
func: Default::default(),
|
func: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set that this function is main entry point
|
/// Set that this function is main entry point
|
||||||
pub fn main(mut self) -> Self {
|
pub fn main(mut self) -> Self {
|
||||||
self.func.is_main = true;
|
self.func.is_main = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start signature builder of the function
|
/// Start signature builder of the function
|
||||||
pub fn signature(self) -> SignatureBuilder<Self> {
|
pub fn signature(self) -> SignatureBuilder<Self> {
|
||||||
SignatureBuilder::with_callback(self)
|
SignatureBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Override current signature entirely with new one from known struct
|
/// Override current signature entirely with new one from known struct
|
||||||
pub fn with_signature(mut self, signature: Signature) -> Self {
|
pub fn with_signature(mut self, signature: Signature) -> Self {
|
||||||
self.func.signature = signature;
|
self.func.signature = signature;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start code (body) builder
|
/// Start code (body) builder
|
||||||
pub fn body(self) -> FuncBodyBuilder<Self> {
|
pub fn body(self) -> FuncBodyBuilder<Self> {
|
||||||
FuncBodyBuilder::with_callback(self)
|
FuncBodyBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set body (code) for this function
|
/// Set body (code) for this function
|
||||||
pub fn with_body(mut self, body: elements::FuncBody) -> Self {
|
pub fn with_body(mut self, body: elements::FuncBody) -> Self {
|
||||||
self.func.code = body;
|
self.func.code = body;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finalize current builder spawning resulting struct in the callback
|
/// Finalize current builder spawning resulting struct in the callback
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(self.func)
|
self.callback.invoke(self.func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::FunctionType> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
impl<F> Invoke<elements::FunctionType> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
||||||
@ -334,7 +334,7 @@ impl<F> Invoke<elements::FunctionType> for FunctionBuilder<F> where F: Invoke<Fu
|
|||||||
|
|
||||||
fn invoke(self, signature: elements::FunctionType) -> Self {
|
fn invoke(self, signature: elements::FunctionType) -> Self {
|
||||||
self.with_signature(Signature::Inline(signature))
|
self.with_signature(Signature::Inline(signature))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<u32> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
impl<F> Invoke<u32> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
||||||
@ -342,70 +342,70 @@ impl<F> Invoke<u32> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
|||||||
|
|
||||||
fn invoke(self, type_ref: u32) -> Self {
|
fn invoke(self, type_ref: u32) -> Self {
|
||||||
self.with_signature(Signature::TypeReference(type_ref))
|
self.with_signature(Signature::TypeReference(type_ref))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::FuncBody> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
impl<F> Invoke<elements::FuncBody> for FunctionBuilder<F> where F: Invoke<FunctionDefinition> {
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, body: elements::FuncBody) -> Self::Result {
|
fn invoke(self, body: elements::FuncBody) -> Self::Result {
|
||||||
self.with_body(body)
|
self.with_body(body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// New builder of signature list
|
/// New builder of signature list
|
||||||
pub fn signatures() -> SignaturesBuilder {
|
pub fn signatures() -> SignaturesBuilder {
|
||||||
SignaturesBuilder::new()
|
SignaturesBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// New signature builder
|
/// New signature builder
|
||||||
pub fn signature() -> SignatureBuilder {
|
pub fn signature() -> SignatureBuilder {
|
||||||
SignatureBuilder::new()
|
SignatureBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// New builder of function (signature & body)
|
/// New builder of function (signature & body)
|
||||||
pub fn function() -> FunctionBuilder {
|
pub fn function() -> FunctionBuilder {
|
||||||
FunctionBuilder::new()
|
FunctionBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::{signatures, function};
|
use super::{signatures, function};
|
||||||
use elements;
|
use elements;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn example() {
|
fn example() {
|
||||||
let result = signatures()
|
let result = signatures()
|
||||||
.type_ref().val(1).build()
|
.type_ref().val(1).build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
assert_eq!(result.entries().len(), 1);
|
assert_eq!(result.entries().len(), 1);
|
||||||
|
|
||||||
let result = signatures()
|
let result = signatures()
|
||||||
.signature()
|
.signature()
|
||||||
.param().i32()
|
.param().i32()
|
||||||
.param().i32()
|
.param().i32()
|
||||||
.return_type().i64()
|
.return_type().i64()
|
||||||
.build()
|
.build()
|
||||||
.bind();
|
.bind();
|
||||||
|
|
||||||
assert_eq!(result.len(), 1);
|
assert_eq!(result.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn func_example() {
|
fn func_example() {
|
||||||
let func = function()
|
let func = function()
|
||||||
.signature()
|
.signature()
|
||||||
.param().i32()
|
.param().i32()
|
||||||
.return_type().i32()
|
.return_type().i32()
|
||||||
.build()
|
.build()
|
||||||
.body()
|
.body()
|
||||||
.with_opcodes(elements::Opcodes::empty())
|
.with_opcodes(elements::Opcodes::empty())
|
||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
assert_eq!(func.code.locals().len(), 0);
|
assert_eq!(func.code.locals().len(), 0);
|
||||||
assert_eq!(func.code.code().elements().len(), 1);
|
assert_eq!(func.code.code().elements().len(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,53 +3,53 @@ use elements;
|
|||||||
|
|
||||||
/// Data segment builder
|
/// Data segment builder
|
||||||
pub struct DataSegmentBuilder<F=Identity> {
|
pub struct DataSegmentBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
// todo: add mapper once multiple memory refs possible
|
// todo: add mapper once multiple memory refs possible
|
||||||
mem_index: u32,
|
mem_index: u32,
|
||||||
offset: elements::InitExpr,
|
offset: elements::InitExpr,
|
||||||
value: Vec<u8>,
|
value: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataSegmentBuilder {
|
impl DataSegmentBuilder {
|
||||||
/// New data segment builder
|
/// New data segment builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
DataSegmentBuilder::with_callback(Identity)
|
DataSegmentBuilder::with_callback(Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> DataSegmentBuilder<F> {
|
impl<F> DataSegmentBuilder<F> {
|
||||||
/// New data segment builder inside the chain context
|
/// New data segment builder inside the chain context
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
DataSegmentBuilder {
|
DataSegmentBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
mem_index: 0,
|
mem_index: 0,
|
||||||
offset: elements::InitExpr::empty(),
|
offset: elements::InitExpr::empty(),
|
||||||
value: Vec::new(),
|
value: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set offset initialization opcode. `End` opcode will be added automatically.
|
/// Set offset initialization opcode. `End` opcode will be added automatically.
|
||||||
pub fn offset(mut self, opcode: elements::Opcode) -> Self {
|
pub fn offset(mut self, opcode: elements::Opcode) -> Self {
|
||||||
self.offset = elements::InitExpr::new(vec![opcode, elements::Opcode::End]);
|
self.offset = elements::InitExpr::new(vec![opcode, elements::Opcode::End]);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the bytes value of the segment
|
/// Set the bytes value of the segment
|
||||||
pub fn value(mut self, value: Vec<u8>) -> Self {
|
pub fn value(mut self, value: Vec<u8>) -> Self {
|
||||||
self.value = value;
|
self.value = value;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> DataSegmentBuilder<F> where F: Invoke<elements::DataSegment> {
|
impl<F> DataSegmentBuilder<F> where F: Invoke<elements::DataSegment> {
|
||||||
/// Finish current builder, spawning resulting struct
|
/// Finish current builder, spawning resulting struct
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(
|
self.callback.invoke(
|
||||||
elements::DataSegment::new(
|
elements::DataSegment::new(
|
||||||
self.mem_index,
|
self.mem_index,
|
||||||
self.offset,
|
self.offset,
|
||||||
self.value,
|
self.value,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,113 +3,113 @@ use elements;
|
|||||||
|
|
||||||
/// Export entry builder
|
/// Export entry builder
|
||||||
pub struct ExportBuilder<F=Identity> {
|
pub struct ExportBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
field: String,
|
field: String,
|
||||||
binding: elements::Internal,
|
binding: elements::Internal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExportBuilder {
|
impl ExportBuilder {
|
||||||
/// New export builder
|
/// New export builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ExportBuilder::with_callback(Identity)
|
ExportBuilder::with_callback(Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> ExportBuilder<F> {
|
impl<F> ExportBuilder<F> {
|
||||||
|
|
||||||
/// New export entry builder in the specified chained context
|
/// New export entry builder in the specified chained context
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
ExportBuilder {
|
ExportBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
field: String::new(),
|
field: String::new(),
|
||||||
binding: elements::Internal::Function(0),
|
binding: elements::Internal::Function(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the field name of the export entry
|
/// Set the field name of the export entry
|
||||||
pub fn field(mut self, field: &str) -> Self {
|
pub fn field(mut self, field: &str) -> Self {
|
||||||
self.field = field.to_owned();
|
self.field = field.to_owned();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify the internal module mapping for this entry
|
/// Specify the internal module mapping for this entry
|
||||||
pub fn with_internal(mut self, external: elements::Internal) -> Self {
|
pub fn with_internal(mut self, external: elements::Internal) -> Self {
|
||||||
self.binding = external;
|
self.binding = external;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start the internal builder for this export entry
|
/// Start the internal builder for this export entry
|
||||||
pub fn internal(self) -> ExportInternalBuilder<Self> {
|
pub fn internal(self) -> ExportInternalBuilder<Self> {
|
||||||
ExportInternalBuilder::with_callback(self)
|
ExportInternalBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> ExportBuilder<F> where F: Invoke<elements::ExportEntry> {
|
impl<F> ExportBuilder<F> where F: Invoke<elements::ExportEntry> {
|
||||||
/// Finalize export entry builder spawning the resulting struct
|
/// Finalize export entry builder spawning the resulting struct
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(elements::ExportEntry::new(self.field, self.binding))
|
self.callback.invoke(elements::ExportEntry::new(self.field, self.binding))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::Internal> for ExportBuilder<F> {
|
impl<F> Invoke<elements::Internal> for ExportBuilder<F> {
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
fn invoke(self, val: elements::Internal) -> Self {
|
fn invoke(self, val: elements::Internal) -> Self {
|
||||||
self.with_internal(val)
|
self.with_internal(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal mapping builder for export entry
|
/// Internal mapping builder for export entry
|
||||||
pub struct ExportInternalBuilder<F=Identity> {
|
pub struct ExportInternalBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
binding: elements::Internal,
|
binding: elements::Internal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> ExportInternalBuilder<F> where F: Invoke<elements::Internal> {
|
impl<F> ExportInternalBuilder<F> where F: Invoke<elements::Internal> {
|
||||||
/// New export entry internal mapping for the chained context
|
/// New export entry internal mapping for the chained context
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
ExportInternalBuilder{
|
ExportInternalBuilder{
|
||||||
callback: callback,
|
callback: callback,
|
||||||
binding: elements::Internal::Function(0),
|
binding: elements::Internal::Function(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map to function by index
|
/// Map to function by index
|
||||||
pub fn func(mut self, index: u32) -> F::Result {
|
pub fn func(mut self, index: u32) -> F::Result {
|
||||||
self.binding = elements::Internal::Function(index);
|
self.binding = elements::Internal::Function(index);
|
||||||
self.callback.invoke(self.binding)
|
self.callback.invoke(self.binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map to memory
|
/// Map to memory
|
||||||
pub fn memory(mut self, index: u32) -> F::Result {
|
pub fn memory(mut self, index: u32) -> F::Result {
|
||||||
self.binding = elements::Internal::Memory(index);
|
self.binding = elements::Internal::Memory(index);
|
||||||
self.callback.invoke(self.binding)
|
self.callback.invoke(self.binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map to table
|
/// Map to table
|
||||||
pub fn table(mut self, index: u32) -> F::Result {
|
pub fn table(mut self, index: u32) -> F::Result {
|
||||||
self.binding = elements::Internal::Table(index);
|
self.binding = elements::Internal::Table(index);
|
||||||
self.callback.invoke(self.binding)
|
self.callback.invoke(self.binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map to global
|
/// Map to global
|
||||||
pub fn global(mut self, index: u32) -> F::Result {
|
pub fn global(mut self, index: u32) -> F::Result {
|
||||||
self.binding = elements::Internal::Global(index);
|
self.binding = elements::Internal::Global(index);
|
||||||
self.callback.invoke(self.binding)
|
self.callback.invoke(self.binding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// New builder for export entry
|
/// New builder for export entry
|
||||||
pub fn export() -> ExportBuilder {
|
pub fn export() -> ExportBuilder {
|
||||||
ExportBuilder::new()
|
ExportBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::export;
|
use super::export;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn example() {
|
fn example() {
|
||||||
let entry = export().field("memory").internal().memory(0).build();
|
let entry = export().field("memory").internal().memory(0).build();
|
||||||
assert_eq!(entry.field(), "memory");
|
assert_eq!(entry.field(), "memory");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,87 +4,87 @@ use elements;
|
|||||||
|
|
||||||
/// Global builder
|
/// Global builder
|
||||||
pub struct GlobalBuilder<F=Identity> {
|
pub struct GlobalBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
value_type: elements::ValueType,
|
value_type: elements::ValueType,
|
||||||
is_mutable: bool,
|
is_mutable: bool,
|
||||||
init_expr: elements::InitExpr,
|
init_expr: elements::InitExpr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalBuilder {
|
impl GlobalBuilder {
|
||||||
/// New global builder
|
/// New global builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
GlobalBuilder::with_callback(Identity)
|
GlobalBuilder::with_callback(Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> GlobalBuilder<F> {
|
impl<F> GlobalBuilder<F> {
|
||||||
/// New global builder with callback (in chained context)
|
/// New global builder with callback (in chained context)
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
GlobalBuilder {
|
GlobalBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
value_type: elements::ValueType::I32,
|
value_type: elements::ValueType::I32,
|
||||||
init_expr: elements::InitExpr::empty(),
|
init_expr: elements::InitExpr::empty(),
|
||||||
is_mutable: false,
|
is_mutable: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set/override resulting global type
|
/// Set/override resulting global type
|
||||||
pub fn with_type(mut self, value_type: elements::ValueType) -> Self {
|
pub fn with_type(mut self, value_type: elements::ValueType) -> Self {
|
||||||
self.value_type = value_type;
|
self.value_type = value_type;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set mutabilty to true
|
/// Set mutabilty to true
|
||||||
pub fn mutable(mut self) -> Self {
|
pub fn mutable(mut self) -> Self {
|
||||||
self.is_mutable = true;
|
self.is_mutable = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set initialization expression opcode for this global (`end` opcode will be added automatically)
|
/// Set initialization expression opcode for this global (`end` opcode will be added automatically)
|
||||||
pub fn init_expr(mut self, opcode: elements::Opcode) -> Self {
|
pub fn init_expr(mut self, opcode: elements::Opcode) -> Self {
|
||||||
self.init_expr = elements::InitExpr::new(vec![opcode, elements::Opcode::End]);
|
self.init_expr = elements::InitExpr::new(vec![opcode, elements::Opcode::End]);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start value type builder
|
/// Start value type builder
|
||||||
pub fn value_type(self) -> ValueTypeBuilder<Self> {
|
pub fn value_type(self) -> ValueTypeBuilder<Self> {
|
||||||
ValueTypeBuilder::with_callback(self)
|
ValueTypeBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> GlobalBuilder<F> where F: Invoke<elements::GlobalEntry> {
|
impl<F> GlobalBuilder<F> where F: Invoke<elements::GlobalEntry> {
|
||||||
/// Finalize current builder spawning resulting struct
|
/// Finalize current builder spawning resulting struct
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(
|
self.callback.invoke(
|
||||||
elements::GlobalEntry::new(
|
elements::GlobalEntry::new(
|
||||||
elements::GlobalType::new(self.value_type, self.is_mutable),
|
elements::GlobalType::new(self.value_type, self.is_mutable),
|
||||||
self.init_expr,
|
self.init_expr,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::ValueType> for GlobalBuilder<F> {
|
impl<F> Invoke<elements::ValueType> for GlobalBuilder<F> {
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
fn invoke(self, the_type: elements::ValueType) -> Self {
|
fn invoke(self, the_type: elements::ValueType) -> Self {
|
||||||
self.with_type(the_type)
|
self.with_type(the_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// New builder for export entry
|
/// New builder for export entry
|
||||||
pub fn global() -> GlobalBuilder {
|
pub fn global() -> GlobalBuilder {
|
||||||
GlobalBuilder::new()
|
GlobalBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::global;
|
use super::global;
|
||||||
use elements;
|
use elements;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn example() {
|
fn example() {
|
||||||
let entry = global().value_type().i32().build();
|
let entry = global().value_type().i32().build();
|
||||||
assert_eq!(entry.global_type().content_type(), elements::ValueType::I32);
|
assert_eq!(entry.global_type().content_type(), elements::ValueType::I32);
|
||||||
assert_eq!(entry.global_type().is_mutable(), false);
|
assert_eq!(entry.global_type().is_mutable(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,127 +3,127 @@ use elements;
|
|||||||
|
|
||||||
/// Import builder
|
/// Import builder
|
||||||
pub struct ImportBuilder<F=Identity> {
|
pub struct ImportBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
module: String,
|
module: String,
|
||||||
field: String,
|
field: String,
|
||||||
binding: elements::External,
|
binding: elements::External,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImportBuilder {
|
impl ImportBuilder {
|
||||||
/// New import builder
|
/// New import builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ImportBuilder::with_callback(Identity)
|
ImportBuilder::with_callback(Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> ImportBuilder<F> {
|
impl<F> ImportBuilder<F> {
|
||||||
/// New import builder with callback (in chained context)
|
/// New import builder with callback (in chained context)
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
ImportBuilder {
|
ImportBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
module: String::new(),
|
module: String::new(),
|
||||||
field: String::new(),
|
field: String::new(),
|
||||||
binding: elements::External::Function(0),
|
binding: elements::External::Function(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set/override module name
|
/// Set/override module name
|
||||||
pub fn module(mut self, name: &str) -> Self {
|
pub fn module(mut self, name: &str) -> Self {
|
||||||
self.module = name.to_owned();
|
self.module = name.to_owned();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set/override field name
|
/// Set/override field name
|
||||||
pub fn field(mut self, name: &str) -> Self {
|
pub fn field(mut self, name: &str) -> Self {
|
||||||
self.field = name.to_owned();
|
self.field = name.to_owned();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set/override both module name and field name
|
/// Set/override both module name and field name
|
||||||
pub fn path(self, module: &str, field: &str) -> Self {
|
pub fn path(self, module: &str, field: &str) -> Self {
|
||||||
self.module(module).field(field)
|
self.module(module).field(field)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set/override external mapping for this import
|
/// Set/override external mapping for this import
|
||||||
pub fn with_external(mut self, external: elements::External) -> Self {
|
pub fn with_external(mut self, external: elements::External) -> Self {
|
||||||
self.binding = external;
|
self.binding = external;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start new external mapping builder
|
/// Start new external mapping builder
|
||||||
pub fn external(self) -> ImportExternalBuilder<Self> {
|
pub fn external(self) -> ImportExternalBuilder<Self> {
|
||||||
ImportExternalBuilder::with_callback(self)
|
ImportExternalBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> ImportBuilder<F> where F: Invoke<elements::ImportEntry> {
|
impl<F> ImportBuilder<F> where F: Invoke<elements::ImportEntry> {
|
||||||
/// Finalize current builder spawning the resulting struct
|
/// Finalize current builder spawning the resulting struct
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(elements::ImportEntry::new(self.module, self.field, self.binding))
|
self.callback.invoke(elements::ImportEntry::new(self.module, self.field, self.binding))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::External> for ImportBuilder<F> {
|
impl<F> Invoke<elements::External> for ImportBuilder<F> {
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
fn invoke(self, val: elements::External) -> Self {
|
fn invoke(self, val: elements::External) -> Self {
|
||||||
self.with_external(val)
|
self.with_external(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Import to external mapping builder
|
/// Import to external mapping builder
|
||||||
pub struct ImportExternalBuilder<F=Identity> {
|
pub struct ImportExternalBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
binding: elements::External,
|
binding: elements::External,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> ImportExternalBuilder<F> where F: Invoke<elements::External> {
|
impl<F> ImportExternalBuilder<F> where F: Invoke<elements::External> {
|
||||||
/// New import to external mapping builder with callback (in chained context)
|
/// New import to external mapping builder with callback (in chained context)
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
ImportExternalBuilder{
|
ImportExternalBuilder{
|
||||||
callback: callback,
|
callback: callback,
|
||||||
binding: elements::External::Function(0),
|
binding: elements::External::Function(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function mapping with type reference
|
/// Function mapping with type reference
|
||||||
pub fn func(mut self, index: u32) -> F::Result {
|
pub fn func(mut self, index: u32) -> F::Result {
|
||||||
self.binding = elements::External::Function(index);
|
self.binding = elements::External::Function(index);
|
||||||
self.callback.invoke(self.binding)
|
self.callback.invoke(self.binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Memory mapping with specified limits
|
/// Memory mapping with specified limits
|
||||||
pub fn memory(mut self, min: u32, max: Option<u32>) -> F::Result {
|
pub fn memory(mut self, min: u32, max: Option<u32>) -> F::Result {
|
||||||
self.binding = elements::External::Memory(elements::MemoryType::new(min, max));
|
self.binding = elements::External::Memory(elements::MemoryType::new(min, max));
|
||||||
self.callback.invoke(self.binding)
|
self.callback.invoke(self.binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Table mapping with specified limits
|
/// Table mapping with specified limits
|
||||||
pub fn table(mut self, min: u32, max: Option<u32>) -> F::Result {
|
pub fn table(mut self, min: u32, max: Option<u32>) -> F::Result {
|
||||||
self.binding = elements::External::Table(elements::TableType::new(min, max));
|
self.binding = elements::External::Table(elements::TableType::new(min, max));
|
||||||
self.callback.invoke(self.binding)
|
self.callback.invoke(self.binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Global mapping with speciifed type and mutability
|
/// Global mapping with speciifed type and mutability
|
||||||
pub fn global(mut self, value_type: elements::ValueType, is_mut: bool) -> F::Result {
|
pub fn global(mut self, value_type: elements::ValueType, is_mut: bool) -> F::Result {
|
||||||
self.binding = elements::External::Global(elements::GlobalType::new(value_type, is_mut));
|
self.binding = elements::External::Global(elements::GlobalType::new(value_type, is_mut));
|
||||||
self.callback.invoke(self.binding)
|
self.callback.invoke(self.binding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// New builder for import entry
|
/// New builder for import entry
|
||||||
pub fn import() -> ImportBuilder {
|
pub fn import() -> ImportBuilder {
|
||||||
ImportBuilder::new()
|
ImportBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::import;
|
use super::import;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn example() {
|
fn example() {
|
||||||
let entry = import().module("env").field("memory").external().memory(256, Some(256)).build();
|
let entry = import().module("env").field("memory").external().memory(256, Some(256)).build();
|
||||||
|
|
||||||
assert_eq!(entry.module(), "env");
|
assert_eq!(entry.module(), "env");
|
||||||
assert_eq!(entry.field(), "memory");
|
assert_eq!(entry.field(), "memory");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,81 +4,81 @@ use super::invoke::{Invoke, Identity};
|
|||||||
/// Memory definition struct
|
/// Memory definition struct
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MemoryDefinition {
|
pub struct MemoryDefinition {
|
||||||
/// Minimum memory size
|
/// Minimum memory size
|
||||||
pub min: u32,
|
pub min: u32,
|
||||||
/// Maximum memory size
|
/// Maximum memory size
|
||||||
pub max: Option<u32>,
|
pub max: Option<u32>,
|
||||||
/// Memory data segments (static regions)
|
/// Memory data segments (static regions)
|
||||||
pub data: Vec<MemoryDataDefinition>,
|
pub data: Vec<MemoryDataDefinition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Memory static region entry definition
|
/// Memory static region entry definition
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MemoryDataDefinition {
|
pub struct MemoryDataDefinition {
|
||||||
/// Segment initialization expression for offset
|
/// Segment initialization expression for offset
|
||||||
pub offset: elements::InitExpr,
|
pub offset: elements::InitExpr,
|
||||||
/// Raw bytes of static region
|
/// Raw bytes of static region
|
||||||
pub values: Vec<u8>,
|
pub values: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Memory and static regions builder
|
/// Memory and static regions builder
|
||||||
pub struct MemoryBuilder<F=Identity> {
|
pub struct MemoryBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
memory: MemoryDefinition,
|
memory: MemoryDefinition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryBuilder {
|
impl MemoryBuilder {
|
||||||
/// New memory builder
|
/// New memory builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
MemoryBuilder::with_callback(Identity)
|
MemoryBuilder::with_callback(Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> MemoryBuilder<F> where F: Invoke<MemoryDefinition> {
|
impl<F> MemoryBuilder<F> where F: Invoke<MemoryDefinition> {
|
||||||
/// New memory builder with callback (in chained context)
|
/// New memory builder with callback (in chained context)
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
MemoryBuilder {
|
MemoryBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
memory: Default::default(),
|
memory: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set/override minimum size
|
/// Set/override minimum size
|
||||||
pub fn with_min(mut self, min: u32) -> Self {
|
pub fn with_min(mut self, min: u32) -> Self {
|
||||||
self.memory.min = min;
|
self.memory.min = min;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set/override maximum size
|
/// Set/override maximum size
|
||||||
pub fn with_max(mut self, max: Option<u32>) -> Self {
|
pub fn with_max(mut self, max: Option<u32>) -> Self {
|
||||||
self.memory.max = max;
|
self.memory.max = max;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push new static region with initialized offset expression and raw bytes
|
/// Push new static region with initialized offset expression and raw bytes
|
||||||
pub fn with_data(mut self, index: u32, values: Vec<u8>) -> Self {
|
pub fn with_data(mut self, index: u32, values: Vec<u8>) -> Self {
|
||||||
self.memory.data.push(MemoryDataDefinition {
|
self.memory.data.push(MemoryDataDefinition {
|
||||||
offset: elements::InitExpr::new(vec![
|
offset: elements::InitExpr::new(vec![
|
||||||
elements::Opcode::I32Const(index as i32),
|
elements::Opcode::I32Const(index as i32),
|
||||||
elements::Opcode::End,
|
elements::Opcode::End,
|
||||||
]),
|
]),
|
||||||
values: values,
|
values: values,
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finalize current builder, spawning resulting struct
|
/// Finalize current builder, spawning resulting struct
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(self.memory)
|
self.callback.invoke(self.memory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MemoryDefinition {
|
impl Default for MemoryDefinition {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
MemoryDefinition {
|
MemoryDefinition {
|
||||||
min: 1,
|
min: 1,
|
||||||
max: None,
|
max: None,
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,91 +2,91 @@ use super::invoke::{Invoke, Identity};
|
|||||||
use elements;
|
use elements;
|
||||||
|
|
||||||
pub struct ValueTypeBuilder<F=Identity> {
|
pub struct ValueTypeBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> ValueTypeBuilder<F> where F: Invoke<elements::ValueType> {
|
impl<F> ValueTypeBuilder<F> where F: Invoke<elements::ValueType> {
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
ValueTypeBuilder { callback: callback }
|
ValueTypeBuilder { callback: callback }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn i32(self) -> F::Result {
|
pub fn i32(self) -> F::Result {
|
||||||
self.callback.invoke(elements::ValueType::I32)
|
self.callback.invoke(elements::ValueType::I32)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn i64(self) -> F::Result {
|
pub fn i64(self) -> F::Result {
|
||||||
self.callback.invoke(elements::ValueType::I64)
|
self.callback.invoke(elements::ValueType::I64)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn f32(self) -> F::Result {
|
pub fn f32(self) -> F::Result {
|
||||||
self.callback.invoke(elements::ValueType::F32)
|
self.callback.invoke(elements::ValueType::F32)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn f64(self) -> F::Result {
|
pub fn f64(self) -> F::Result {
|
||||||
self.callback.invoke(elements::ValueType::F64)
|
self.callback.invoke(elements::ValueType::F64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OptionalValueTypeBuilder<F=Identity> {
|
pub struct OptionalValueTypeBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> OptionalValueTypeBuilder<F> where F: Invoke<Option<elements::ValueType>> {
|
impl<F> OptionalValueTypeBuilder<F> where F: Invoke<Option<elements::ValueType>> {
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
OptionalValueTypeBuilder { callback: callback }
|
OptionalValueTypeBuilder { callback: callback }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn i32(self) -> F::Result {
|
pub fn i32(self) -> F::Result {
|
||||||
self.callback.invoke(Some(elements::ValueType::I32))
|
self.callback.invoke(Some(elements::ValueType::I32))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn i64(self) -> F::Result {
|
pub fn i64(self) -> F::Result {
|
||||||
self.callback.invoke(Some(elements::ValueType::I64))
|
self.callback.invoke(Some(elements::ValueType::I64))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn f32(self) -> F::Result {
|
pub fn f32(self) -> F::Result {
|
||||||
self.callback.invoke(Some(elements::ValueType::F32))
|
self.callback.invoke(Some(elements::ValueType::F32))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn f64(self) -> F::Result {
|
pub fn f64(self) -> F::Result {
|
||||||
self.callback.invoke(Some(elements::ValueType::F64))
|
self.callback.invoke(Some(elements::ValueType::F64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ValueTypesBuilder<F=Identity> {
|
pub struct ValueTypesBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
value_types: Vec<elements::ValueType>,
|
value_types: Vec<elements::ValueType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> ValueTypesBuilder<F> where F: Invoke<Vec<elements::ValueType>> {
|
impl<F> ValueTypesBuilder<F> where F: Invoke<Vec<elements::ValueType>> {
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
ValueTypesBuilder {
|
ValueTypesBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
value_types: Vec::new(),
|
value_types: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn i32(mut self) -> Self {
|
pub fn i32(mut self) -> Self {
|
||||||
self.value_types.push(elements::ValueType::I32);
|
self.value_types.push(elements::ValueType::I32);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn i64(mut self) -> Self {
|
pub fn i64(mut self) -> Self {
|
||||||
self.value_types.push(elements::ValueType::I64);
|
self.value_types.push(elements::ValueType::I64);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn f32(mut self) -> Self {
|
pub fn f32(mut self) -> Self {
|
||||||
self.value_types.push(elements::ValueType::F32);
|
self.value_types.push(elements::ValueType::F32);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn f64(mut self) -> Self {
|
pub fn f64(mut self) -> Self {
|
||||||
self.value_types.push(elements::ValueType::F64);
|
self.value_types.push(elements::ValueType::F64);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(self.value_types)
|
self.callback.invoke(self.value_types)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,8 +12,8 @@ mod global;
|
|||||||
mod data;
|
mod data;
|
||||||
|
|
||||||
pub use self::code::{
|
pub use self::code::{
|
||||||
signatures, signature, function, SignatureBuilder, SignaturesBuilder,
|
signatures, signature, function, SignatureBuilder, SignaturesBuilder,
|
||||||
FunctionBuilder, TypeRefBuilder, FuncBodyBuilder, FunctionDefinition,
|
FunctionBuilder, TypeRefBuilder, FuncBodyBuilder, FunctionDefinition,
|
||||||
};
|
};
|
||||||
pub use self::data::DataSegmentBuilder;
|
pub use self::data::DataSegmentBuilder;
|
||||||
pub use self::export::{export, ExportBuilder, ExportInternalBuilder};
|
pub use self::export::{export, ExportBuilder, ExportInternalBuilder};
|
||||||
|
@ -7,484 +7,484 @@ use elements;
|
|||||||
|
|
||||||
/// Module builder
|
/// Module builder
|
||||||
pub struct ModuleBuilder<F=Identity> {
|
pub struct ModuleBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
module: ModuleScaffold,
|
module: ModuleScaffold,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Location of the internal module function
|
/// Location of the internal module function
|
||||||
pub struct CodeLocation {
|
pub struct CodeLocation {
|
||||||
/// Location (index in 'functions' section) of the signature
|
/// Location (index in 'functions' section) of the signature
|
||||||
pub signature: u32,
|
pub signature: u32,
|
||||||
/// Location (index in the 'code' section) of the body
|
/// Location (index in the 'code' section) of the body
|
||||||
pub body: u32,
|
pub body: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ModuleScaffold {
|
struct ModuleScaffold {
|
||||||
pub types: elements::TypeSection,
|
pub types: elements::TypeSection,
|
||||||
pub import: elements::ImportSection,
|
pub import: elements::ImportSection,
|
||||||
pub functions: elements::FunctionSection,
|
pub functions: elements::FunctionSection,
|
||||||
pub table: elements::TableSection,
|
pub table: elements::TableSection,
|
||||||
pub memory: elements::MemorySection,
|
pub memory: elements::MemorySection,
|
||||||
pub global: elements::GlobalSection,
|
pub global: elements::GlobalSection,
|
||||||
pub export: elements::ExportSection,
|
pub export: elements::ExportSection,
|
||||||
pub start: Option<u32>,
|
pub start: Option<u32>,
|
||||||
pub element: elements::ElementSection,
|
pub element: elements::ElementSection,
|
||||||
pub code: elements::CodeSection,
|
pub code: elements::CodeSection,
|
||||||
pub data: elements::DataSection,
|
pub data: elements::DataSection,
|
||||||
pub other: Vec<elements::Section>,
|
pub other: Vec<elements::Section>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<elements::Module> for ModuleScaffold {
|
impl From<elements::Module> for ModuleScaffold {
|
||||||
fn from(module: elements::Module) -> Self {
|
fn from(module: elements::Module) -> Self {
|
||||||
let mut types: Option<elements::TypeSection> = None;
|
let mut types: Option<elements::TypeSection> = None;
|
||||||
let mut import: Option<elements::ImportSection> = None;
|
let mut import: Option<elements::ImportSection> = None;
|
||||||
let mut funcs: Option<elements::FunctionSection> = None;
|
let mut funcs: Option<elements::FunctionSection> = None;
|
||||||
let mut table: Option<elements::TableSection> = None;
|
let mut table: Option<elements::TableSection> = None;
|
||||||
let mut memory: Option<elements::MemorySection> = None;
|
let mut memory: Option<elements::MemorySection> = None;
|
||||||
let mut global: Option<elements::GlobalSection> = None;
|
let mut global: Option<elements::GlobalSection> = None;
|
||||||
let mut export: Option<elements::ExportSection> = None;
|
let mut export: Option<elements::ExportSection> = None;
|
||||||
let mut start: Option<u32> = None;
|
let mut start: Option<u32> = None;
|
||||||
let mut element: Option<elements::ElementSection> = None;
|
let mut element: Option<elements::ElementSection> = None;
|
||||||
let mut code: Option<elements::CodeSection> = None;
|
let mut code: Option<elements::CodeSection> = None;
|
||||||
let mut data: Option<elements::DataSection> = None;
|
let mut data: Option<elements::DataSection> = None;
|
||||||
|
|
||||||
let mut sections = module.into_sections();
|
let mut sections = module.into_sections();
|
||||||
while let Some(section) = sections.pop() {
|
while let Some(section) = sections.pop() {
|
||||||
match section {
|
match section {
|
||||||
elements::Section::Type(sect) => { types = Some(sect); }
|
elements::Section::Type(sect) => { types = Some(sect); }
|
||||||
elements::Section::Import(sect) => { import = Some(sect); }
|
elements::Section::Import(sect) => { import = Some(sect); }
|
||||||
elements::Section::Function(sect) => { funcs = Some(sect); }
|
elements::Section::Function(sect) => { funcs = Some(sect); }
|
||||||
elements::Section::Table(sect) => { table = Some(sect); }
|
elements::Section::Table(sect) => { table = Some(sect); }
|
||||||
elements::Section::Memory(sect) => { memory = Some(sect); }
|
elements::Section::Memory(sect) => { memory = Some(sect); }
|
||||||
elements::Section::Global(sect) => { global = Some(sect); }
|
elements::Section::Global(sect) => { global = Some(sect); }
|
||||||
elements::Section::Export(sect) => { export = Some(sect); }
|
elements::Section::Export(sect) => { export = Some(sect); }
|
||||||
elements::Section::Start(index) => { start = Some(index); }
|
elements::Section::Start(index) => { start = Some(index); }
|
||||||
elements::Section::Element(sect) => { element = Some(sect); }
|
elements::Section::Element(sect) => { element = Some(sect); }
|
||||||
elements::Section::Code(sect) => { code = Some(sect); }
|
elements::Section::Code(sect) => { code = Some(sect); }
|
||||||
elements::Section::Data(sect) => { data = Some(sect); }
|
elements::Section::Data(sect) => { data = Some(sect); }
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleScaffold {
|
ModuleScaffold {
|
||||||
types: types.unwrap_or_default(),
|
types: types.unwrap_or_default(),
|
||||||
import: import.unwrap_or_default(),
|
import: import.unwrap_or_default(),
|
||||||
functions: funcs.unwrap_or_default(),
|
functions: funcs.unwrap_or_default(),
|
||||||
table: table.unwrap_or_default(),
|
table: table.unwrap_or_default(),
|
||||||
memory: memory.unwrap_or_default(),
|
memory: memory.unwrap_or_default(),
|
||||||
global: global.unwrap_or_default(),
|
global: global.unwrap_or_default(),
|
||||||
export: export.unwrap_or_default(),
|
export: export.unwrap_or_default(),
|
||||||
start: start,
|
start: start,
|
||||||
element: element.unwrap_or_default(),
|
element: element.unwrap_or_default(),
|
||||||
code: code.unwrap_or_default(),
|
code: code.unwrap_or_default(),
|
||||||
data: data.unwrap_or_default(),
|
data: data.unwrap_or_default(),
|
||||||
other: sections,
|
other: sections,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ModuleScaffold> for elements::Module {
|
impl From<ModuleScaffold> for elements::Module {
|
||||||
fn from(module: ModuleScaffold) -> Self {
|
fn from(module: ModuleScaffold) -> Self {
|
||||||
let mut sections = Vec::new();
|
let mut sections = Vec::new();
|
||||||
|
|
||||||
let types = module.types;
|
let types = module.types;
|
||||||
if types.types().len() > 0 {
|
if types.types().len() > 0 {
|
||||||
sections.push(elements::Section::Type(types));
|
sections.push(elements::Section::Type(types));
|
||||||
}
|
}
|
||||||
let import = module.import;
|
let import = module.import;
|
||||||
if import.entries().len() > 0 {
|
if import.entries().len() > 0 {
|
||||||
sections.push(elements::Section::Import(import));
|
sections.push(elements::Section::Import(import));
|
||||||
}
|
}
|
||||||
let functions = module.functions;
|
let functions = module.functions;
|
||||||
if functions.entries().len() > 0 {
|
if functions.entries().len() > 0 {
|
||||||
sections.push(elements::Section::Function(functions));
|
sections.push(elements::Section::Function(functions));
|
||||||
}
|
}
|
||||||
let table = module.table;
|
let table = module.table;
|
||||||
if table.entries().len() > 0 {
|
if table.entries().len() > 0 {
|
||||||
sections.push(elements::Section::Table(table));
|
sections.push(elements::Section::Table(table));
|
||||||
}
|
}
|
||||||
let memory = module.memory;
|
let memory = module.memory;
|
||||||
if memory.entries().len() > 0 {
|
if memory.entries().len() > 0 {
|
||||||
sections.push(elements::Section::Memory(memory));
|
sections.push(elements::Section::Memory(memory));
|
||||||
}
|
}
|
||||||
let global = module.global;
|
let global = module.global;
|
||||||
if global.entries().len() > 0 {
|
if global.entries().len() > 0 {
|
||||||
sections.push(elements::Section::Global(global));
|
sections.push(elements::Section::Global(global));
|
||||||
}
|
}
|
||||||
let export = module.export;
|
let export = module.export;
|
||||||
if export.entries().len() > 0 {
|
if export.entries().len() > 0 {
|
||||||
sections.push(elements::Section::Export(export));
|
sections.push(elements::Section::Export(export));
|
||||||
}
|
}
|
||||||
if let Some(start) = module.start {
|
if let Some(start) = module.start {
|
||||||
sections.push(elements::Section::Start(start));
|
sections.push(elements::Section::Start(start));
|
||||||
}
|
}
|
||||||
let element = module.element;
|
let element = module.element;
|
||||||
if element.entries().len() > 0 {
|
if element.entries().len() > 0 {
|
||||||
sections.push(elements::Section::Element(element));
|
sections.push(elements::Section::Element(element));
|
||||||
}
|
}
|
||||||
let code = module.code;
|
let code = module.code;
|
||||||
if code.bodies().len() > 0 {
|
if code.bodies().len() > 0 {
|
||||||
sections.push(elements::Section::Code(code));
|
sections.push(elements::Section::Code(code));
|
||||||
}
|
}
|
||||||
let data = module.data;
|
let data = module.data;
|
||||||
if data.entries().len() > 0 {
|
if data.entries().len() > 0 {
|
||||||
sections.push(elements::Section::Data(data));
|
sections.push(elements::Section::Data(data));
|
||||||
}
|
}
|
||||||
sections.extend(module.other);
|
sections.extend(module.other);
|
||||||
elements::Module::new(sections)
|
elements::Module::new(sections)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleBuilder {
|
impl ModuleBuilder {
|
||||||
/// New empty module builder
|
/// New empty module builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ModuleBuilder::with_callback(Identity)
|
ModuleBuilder::with_callback(Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
|
impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
|
||||||
/// New module builder with bound callback
|
/// New module builder with bound callback
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
ModuleBuilder {
|
ModuleBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
module: Default::default(),
|
module: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder from raw module
|
/// Builder from raw module
|
||||||
pub fn with_module(mut self, module: elements::Module) -> Self {
|
pub fn with_module(mut self, module: elements::Module) -> Self {
|
||||||
self.module = module.into();
|
self.module = module.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fill module with sections from iterator
|
/// Fill module with sections from iterator
|
||||||
pub fn with_sections<I>(mut self, sections: I) -> Self
|
pub fn with_sections<I>(mut self, sections: I) -> Self
|
||||||
where I: IntoIterator<Item=elements::Section>
|
where I: IntoIterator<Item=elements::Section>
|
||||||
{
|
{
|
||||||
self.module.other.extend(sections);
|
self.module.other.extend(sections);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add additional section
|
/// Add additional section
|
||||||
pub fn with_section(mut self, section: elements::Section) -> Self {
|
pub fn with_section(mut self, section: elements::Section) -> Self {
|
||||||
self.module.other.push(section);
|
self.module.other.push(section);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Binds to the type section, creates additional types when required
|
/// Binds to the type section, creates additional types when required
|
||||||
pub fn with_signatures(mut self, bindings: code::SignatureBindings) -> Self {
|
pub fn with_signatures(mut self, bindings: code::SignatureBindings) -> Self {
|
||||||
self.push_signatures(bindings);
|
self.push_signatures(bindings);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push stand-alone function definition, creating sections, signature and code blocks
|
/// Push stand-alone function definition, creating sections, signature and code blocks
|
||||||
/// in corresponding sections.
|
/// in corresponding sections.
|
||||||
/// `FunctionDefinition` can be build using `builder::function` builder
|
/// `FunctionDefinition` can be build using `builder::function` builder
|
||||||
pub fn push_function(&mut self, func: code::FunctionDefinition) -> CodeLocation {
|
pub fn push_function(&mut self, func: code::FunctionDefinition) -> CodeLocation {
|
||||||
let signature = func.signature;
|
let signature = func.signature;
|
||||||
let body = func.code;
|
let body = func.code;
|
||||||
|
|
||||||
let type_ref = self.resolve_type_ref(signature);
|
let type_ref = self.resolve_type_ref(signature);
|
||||||
|
|
||||||
self.module.functions.entries_mut().push(elements::Func::new(type_ref));
|
self.module.functions.entries_mut().push(elements::Func::new(type_ref));
|
||||||
let signature_index = self.module.functions.entries_mut().len() as u32 - 1;
|
let signature_index = self.module.functions.entries_mut().len() as u32 - 1;
|
||||||
self.module.code.bodies_mut().push(body);
|
self.module.code.bodies_mut().push(body);
|
||||||
let body_index = self.module.code.bodies_mut().len() as u32 - 1;
|
let body_index = self.module.code.bodies_mut().len() as u32 - 1;
|
||||||
|
|
||||||
if func.is_main {
|
if func.is_main {
|
||||||
self.module.start = Some(body_index);
|
self.module.start = Some(body_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
CodeLocation {
|
CodeLocation {
|
||||||
signature: signature_index,
|
signature: signature_index,
|
||||||
body: body_index,
|
body: body_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push linear memory region
|
/// Push linear memory region
|
||||||
pub fn push_memory(&mut self, mut memory: memory::MemoryDefinition) -> u32 {
|
pub fn push_memory(&mut self, mut memory: memory::MemoryDefinition) -> u32 {
|
||||||
let entries = self.module.memory.entries_mut();
|
let entries = self.module.memory.entries_mut();
|
||||||
entries.push(elements::MemoryType::new(memory.min, memory.max));
|
entries.push(elements::MemoryType::new(memory.min, memory.max));
|
||||||
let memory_index = (entries.len() - 1) as u32;
|
let memory_index = (entries.len() - 1) as u32;
|
||||||
for data in memory.data.drain(..) {
|
for data in memory.data.drain(..) {
|
||||||
self.module.data.entries_mut()
|
self.module.data.entries_mut()
|
||||||
.push(elements::DataSegment::new(memory_index, data.offset, data.values))
|
.push(elements::DataSegment::new(memory_index, data.offset, data.values))
|
||||||
}
|
}
|
||||||
memory_index
|
memory_index
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push table
|
/// Push table
|
||||||
pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 {
|
pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 {
|
||||||
let entries = self.module.table.entries_mut();
|
let entries = self.module.table.entries_mut();
|
||||||
entries.push(elements::TableType::new(table.min, table.max));
|
entries.push(elements::TableType::new(table.min, table.max));
|
||||||
let table_index = (entries.len() - 1) as u32;
|
let table_index = (entries.len() - 1) as u32;
|
||||||
for entry in table.elements.drain(..) {
|
for entry in table.elements.drain(..) {
|
||||||
self.module.element.entries_mut()
|
self.module.element.entries_mut()
|
||||||
.push(elements::ElementSegment::new(table_index, entry.offset, entry.values))
|
.push(elements::ElementSegment::new(table_index, entry.offset, entry.values))
|
||||||
}
|
}
|
||||||
table_index
|
table_index
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 {
|
fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 {
|
||||||
match signature {
|
match signature {
|
||||||
code::Signature::Inline(func_type) => {
|
code::Signature::Inline(func_type) => {
|
||||||
// todo: maybe search for existing type
|
// todo: maybe search for existing type
|
||||||
self.module.types.types_mut().push(elements::Type::Function(func_type));
|
self.module.types.types_mut().push(elements::Type::Function(func_type));
|
||||||
self.module.types.types().len() as u32 - 1
|
self.module.types.types().len() as u32 - 1
|
||||||
}
|
}
|
||||||
code::Signature::TypeReference(type_ref) => {
|
code::Signature::TypeReference(type_ref) => {
|
||||||
type_ref
|
type_ref
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push one function signature, returning it's calling index.
|
/// Push one function signature, returning it's calling index.
|
||||||
/// Can create corresponding type in type section.
|
/// Can create corresponding type in type section.
|
||||||
pub fn push_signature(&mut self, signature: code::Signature) -> u32 {
|
pub fn push_signature(&mut self, signature: code::Signature) -> u32 {
|
||||||
self.resolve_type_ref(signature)
|
self.resolve_type_ref(signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push signatures in the module, returning corresponding indices of pushed signatures
|
/// Push signatures in the module, returning corresponding indices of pushed signatures
|
||||||
pub fn push_signatures(&mut self, signatures: code::SignatureBindings) -> Vec<u32> {
|
pub fn push_signatures(&mut self, signatures: code::SignatureBindings) -> Vec<u32> {
|
||||||
signatures.into_iter().map(|binding|
|
signatures.into_iter().map(|binding|
|
||||||
self.resolve_type_ref(binding)
|
self.resolve_type_ref(binding)
|
||||||
).collect()
|
).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push import entry to module. Not that it does not update calling indices in
|
/// Push import entry to module. Not that it does not update calling indices in
|
||||||
/// function bodies.
|
/// function bodies.
|
||||||
pub fn push_import(&mut self, import: elements::ImportEntry) -> u32 {
|
pub fn push_import(&mut self, import: elements::ImportEntry) -> u32 {
|
||||||
self.module.import.entries_mut().push(import);
|
self.module.import.entries_mut().push(import);
|
||||||
// todo: actually update calling addresses in function bodies
|
// todo: actually update calling addresses in function bodies
|
||||||
// todo: also batch push
|
// todo: also batch push
|
||||||
|
|
||||||
self.module.import.entries_mut().len() as u32 - 1
|
self.module.import.entries_mut().len() as u32 - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push export entry to module.
|
/// Push export entry to module.
|
||||||
pub fn push_export(&mut self, export: elements::ExportEntry) -> u32 {
|
pub fn push_export(&mut self, export: elements::ExportEntry) -> u32 {
|
||||||
self.module.export.entries_mut().push(export);
|
self.module.export.entries_mut().push(export);
|
||||||
self.module.export.entries_mut().len() as u32 - 1
|
self.module.export.entries_mut().len() as u32 - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add new function using dedicated builder
|
/// Add new function using dedicated builder
|
||||||
pub fn function(self) -> FunctionBuilder<Self> {
|
pub fn function(self) -> FunctionBuilder<Self> {
|
||||||
FunctionBuilder::with_callback(self)
|
FunctionBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add new linear memory using dedicated builder
|
/// Add new linear memory using dedicated builder
|
||||||
pub fn memory(self) -> MemoryBuilder<Self> {
|
pub fn memory(self) -> MemoryBuilder<Self> {
|
||||||
MemoryBuilder::with_callback(self)
|
MemoryBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add new table using dedicated builder
|
/// Add new table using dedicated builder
|
||||||
pub fn table(self) -> TableBuilder<Self> {
|
pub fn table(self) -> TableBuilder<Self> {
|
||||||
TableBuilder::with_callback(self)
|
TableBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define functions section
|
/// Define functions section
|
||||||
pub fn functions(self) -> SignaturesBuilder<Self> {
|
pub fn functions(self) -> SignaturesBuilder<Self> {
|
||||||
SignaturesBuilder::with_callback(self)
|
SignaturesBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// With inserted export entry
|
/// With inserted export entry
|
||||||
pub fn with_export(mut self, entry: elements::ExportEntry) -> Self {
|
pub fn with_export(mut self, entry: elements::ExportEntry) -> Self {
|
||||||
self.module.export.entries_mut().push(entry);
|
self.module.export.entries_mut().push(entry);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// With inserted import entry
|
/// With inserted import entry
|
||||||
pub fn with_import(mut self, entry: elements::ImportEntry) -> Self {
|
pub fn with_import(mut self, entry: elements::ImportEntry) -> Self {
|
||||||
self.module.import.entries_mut().push(entry);
|
self.module.import.entries_mut().push(entry);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Import entry builder
|
/// Import entry builder
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use parity_wasm::builder::module;
|
/// use parity_wasm::builder::module;
|
||||||
///
|
///
|
||||||
/// let module = module()
|
/// let module = module()
|
||||||
/// .import()
|
/// .import()
|
||||||
/// .module("env")
|
/// .module("env")
|
||||||
/// .field("memory")
|
/// .field("memory")
|
||||||
/// .external().memory(256, Some(256))
|
/// .external().memory(256, Some(256))
|
||||||
/// .build()
|
/// .build()
|
||||||
/// .build();
|
/// .build();
|
||||||
///
|
///
|
||||||
/// assert_eq!(module.import_section().expect("import section to exist").entries().len(), 1);
|
/// assert_eq!(module.import_section().expect("import section to exist").entries().len(), 1);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn import(self) -> import::ImportBuilder<Self> {
|
pub fn import(self) -> import::ImportBuilder<Self> {
|
||||||
import::ImportBuilder::with_callback(self)
|
import::ImportBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// With global variable
|
/// With global variable
|
||||||
pub fn with_global(mut self, global: elements::GlobalEntry) -> Self {
|
pub fn with_global(mut self, global: elements::GlobalEntry) -> Self {
|
||||||
self.module.global.entries_mut().push(global);
|
self.module.global.entries_mut().push(global);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// With table
|
/// With table
|
||||||
pub fn with_table(mut self, table: elements::TableType) -> Self {
|
pub fn with_table(mut self, table: elements::TableType) -> Self {
|
||||||
self.module.table.entries_mut().push(table);
|
self.module.table.entries_mut().push(table);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Export entry builder
|
/// Export entry builder
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use parity_wasm::builder::module;
|
/// use parity_wasm::builder::module;
|
||||||
/// use parity_wasm::elements::Opcode::*;
|
/// use parity_wasm::elements::Opcode::*;
|
||||||
///
|
///
|
||||||
/// let module = module()
|
/// let module = module()
|
||||||
/// .global()
|
/// .global()
|
||||||
/// .value_type().i32()
|
/// .value_type().i32()
|
||||||
/// .init_expr(I32Const(0))
|
/// .init_expr(I32Const(0))
|
||||||
/// .build()
|
/// .build()
|
||||||
/// .export()
|
/// .export()
|
||||||
/// .field("_zero")
|
/// .field("_zero")
|
||||||
/// .internal().global(0)
|
/// .internal().global(0)
|
||||||
/// .build()
|
/// .build()
|
||||||
/// .build();
|
/// .build();
|
||||||
///
|
///
|
||||||
/// assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1);
|
/// assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn export(self) -> export::ExportBuilder<Self> {
|
pub fn export(self) -> export::ExportBuilder<Self> {
|
||||||
export::ExportBuilder::with_callback(self)
|
export::ExportBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Glboal entry builder
|
/// Glboal entry builder
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```
|
/// ```
|
||||||
/// use parity_wasm::builder::module;
|
/// use parity_wasm::builder::module;
|
||||||
/// use parity_wasm::elements::Opcode::*;
|
/// use parity_wasm::elements::Opcode::*;
|
||||||
///
|
///
|
||||||
/// let module = module()
|
/// let module = module()
|
||||||
/// .global()
|
/// .global()
|
||||||
/// .value_type().i32()
|
/// .value_type().i32()
|
||||||
/// .init_expr(I32Const(0))
|
/// .init_expr(I32Const(0))
|
||||||
/// .build()
|
/// .build()
|
||||||
/// .build();
|
/// .build();
|
||||||
///
|
///
|
||||||
/// assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1);
|
/// assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn global(self) -> global::GlobalBuilder<Self> {
|
pub fn global(self) -> global::GlobalBuilder<Self> {
|
||||||
global::GlobalBuilder::with_callback(self)
|
global::GlobalBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add data segment to the builder
|
/// Add data segment to the builder
|
||||||
pub fn with_data_segment(mut self, segment: elements::DataSegment) -> Self {
|
pub fn with_data_segment(mut self, segment: elements::DataSegment) -> Self {
|
||||||
self.module.data.entries_mut().push(segment);
|
self.module.data.entries_mut().push(segment);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data entry builder
|
/// Data entry builder
|
||||||
pub fn data(self) -> data::DataSegmentBuilder<Self> {
|
pub fn data(self) -> data::DataSegmentBuilder<Self> {
|
||||||
data::DataSegmentBuilder::with_callback(self)
|
data::DataSegmentBuilder::with_callback(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build module (final step)
|
/// Build module (final step)
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(self.module.into())
|
self.callback.invoke(self.module.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::FunctionSection> for ModuleBuilder<F>
|
impl<F> Invoke<elements::FunctionSection> for ModuleBuilder<F>
|
||||||
where F: Invoke<elements::Module>
|
where F: Invoke<elements::Module>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, section: elements::FunctionSection) -> Self {
|
fn invoke(self, section: elements::FunctionSection) -> Self {
|
||||||
self.with_section(elements::Section::Function(section))
|
self.with_section(elements::Section::Function(section))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<code::SignatureBindings> for ModuleBuilder<F>
|
impl<F> Invoke<code::SignatureBindings> for ModuleBuilder<F>
|
||||||
where F: Invoke<elements::Module>
|
where F: Invoke<elements::Module>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, bindings: code::SignatureBindings) -> Self {
|
fn invoke(self, bindings: code::SignatureBindings) -> Self {
|
||||||
self.with_signatures(bindings)
|
self.with_signatures(bindings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<F> Invoke<code::FunctionDefinition> for ModuleBuilder<F>
|
impl<F> Invoke<code::FunctionDefinition> for ModuleBuilder<F>
|
||||||
where F: Invoke<elements::Module>
|
where F: Invoke<elements::Module>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, def: code::FunctionDefinition) -> Self {
|
fn invoke(self, def: code::FunctionDefinition) -> Self {
|
||||||
let mut b = self;
|
let mut b = self;
|
||||||
b.push_function(def);
|
b.push_function(def);
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<memory::MemoryDefinition> for ModuleBuilder<F>
|
impl<F> Invoke<memory::MemoryDefinition> for ModuleBuilder<F>
|
||||||
where F: Invoke<elements::Module>
|
where F: Invoke<elements::Module>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, def: memory::MemoryDefinition) -> Self {
|
fn invoke(self, def: memory::MemoryDefinition) -> Self {
|
||||||
let mut b = self;
|
let mut b = self;
|
||||||
b.push_memory(def);
|
b.push_memory(def);
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<table::TableDefinition> for ModuleBuilder<F>
|
impl<F> Invoke<table::TableDefinition> for ModuleBuilder<F>
|
||||||
where F: Invoke<elements::Module>
|
where F: Invoke<elements::Module>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, def: table::TableDefinition) -> Self {
|
fn invoke(self, def: table::TableDefinition) -> Self {
|
||||||
let mut b = self;
|
let mut b = self;
|
||||||
b.push_table(def);
|
b.push_table(def);
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::ImportEntry> for ModuleBuilder<F>
|
impl<F> Invoke<elements::ImportEntry> for ModuleBuilder<F>
|
||||||
where F: Invoke<elements::Module>
|
where F: Invoke<elements::Module>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, entry: elements::ImportEntry) -> Self::Result {
|
fn invoke(self, entry: elements::ImportEntry) -> Self::Result {
|
||||||
self.with_import(entry)
|
self.with_import(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::ExportEntry> for ModuleBuilder<F>
|
impl<F> Invoke<elements::ExportEntry> for ModuleBuilder<F>
|
||||||
where F: Invoke<elements::Module>
|
where F: Invoke<elements::Module>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, entry: elements::ExportEntry) -> Self::Result {
|
fn invoke(self, entry: elements::ExportEntry) -> Self::Result {
|
||||||
self.with_export(entry)
|
self.with_export(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::GlobalEntry> for ModuleBuilder<F>
|
impl<F> Invoke<elements::GlobalEntry> for ModuleBuilder<F>
|
||||||
where F: Invoke<elements::Module>
|
where F: Invoke<elements::Module>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, entry: elements::GlobalEntry) -> Self::Result {
|
fn invoke(self, entry: elements::GlobalEntry) -> Self::Result {
|
||||||
self.with_global(entry)
|
self.with_global(entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F>
|
impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F>
|
||||||
where F: Invoke<elements::Module>
|
where F: Invoke<elements::Module>
|
||||||
{
|
{
|
||||||
type Result = Self;
|
type Result = Self;
|
||||||
|
|
||||||
fn invoke(self, segment: elements::DataSegment) -> Self {
|
fn invoke(self, segment: elements::DataSegment) -> Self {
|
||||||
self.with_data_segment(segment)
|
self.with_data_segment(segment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start new module builder
|
/// Start new module builder
|
||||||
@ -492,7 +492,7 @@ impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F>
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use parity_wasm::builder;
|
/// use parity_wasm::builder;
|
||||||
///
|
///
|
||||||
/// let module = builder::module()
|
/// let module = builder::module()
|
||||||
/// .function()
|
/// .function()
|
||||||
/// .signature().param().i32().build()
|
/// .signature().param().i32().build()
|
||||||
@ -505,66 +505,66 @@ impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F>
|
|||||||
/// assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1);
|
/// assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn module() -> ModuleBuilder {
|
pub fn module() -> ModuleBuilder {
|
||||||
ModuleBuilder::new()
|
ModuleBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start builder to extend existing module
|
/// Start builder to extend existing module
|
||||||
pub fn from_module(module: elements::Module) -> ModuleBuilder {
|
pub fn from_module(module: elements::Module) -> ModuleBuilder {
|
||||||
ModuleBuilder::new().with_module(module)
|
ModuleBuilder::new().with_module(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::module;
|
use super::module;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoky() {
|
fn smoky() {
|
||||||
let module = module().build();
|
let module = module().build();
|
||||||
assert_eq!(module.sections().len(), 0);
|
assert_eq!(module.sections().len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn functions() {
|
fn functions() {
|
||||||
let module = module()
|
let module = module()
|
||||||
.function()
|
.function()
|
||||||
.signature().param().i32().build()
|
.signature().param().i32().build()
|
||||||
.body().build()
|
.body().build()
|
||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
assert_eq!(module.type_section().expect("type section to exist").types().len(), 1);
|
assert_eq!(module.type_section().expect("type section to exist").types().len(), 1);
|
||||||
assert_eq!(module.function_section().expect("function section to exist").entries().len(), 1);
|
assert_eq!(module.function_section().expect("function section to exist").entries().len(), 1);
|
||||||
assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1);
|
assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn export() {
|
fn export() {
|
||||||
let module = module()
|
let module = module()
|
||||||
.export().field("call").internal().func(0).build()
|
.export().field("call").internal().func(0).build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1);
|
assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn global() {
|
fn global() {
|
||||||
let module = module()
|
let module = module()
|
||||||
.global().value_type().i64().mutable().init_expr(::elements::Opcode::I64Const(5)).build()
|
.global().value_type().i64().mutable().init_expr(::elements::Opcode::I64Const(5)).build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1);
|
assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn data() {
|
fn data() {
|
||||||
let module = module()
|
let module = module()
|
||||||
.data()
|
.data()
|
||||||
.offset(::elements::Opcode::I32Const(16))
|
.offset(::elements::Opcode::I32Const(16))
|
||||||
.value(vec![0u8, 15, 10, 5, 25])
|
.value(vec![0u8, 15, 10, 5, 25])
|
||||||
.build()
|
.build()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
assert_eq!(module.data_section().expect("data section to exist").entries().len(), 1);
|
assert_eq!(module.data_section().expect("data section to exist").entries().len(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,81 +4,81 @@ use super::invoke::{Invoke, Identity};
|
|||||||
/// Table definition
|
/// Table definition
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TableDefinition {
|
pub struct TableDefinition {
|
||||||
/// Minimum length
|
/// Minimum length
|
||||||
pub min: u32,
|
pub min: u32,
|
||||||
/// Maximum length, if any
|
/// Maximum length, if any
|
||||||
pub max: Option<u32>,
|
pub max: Option<u32>,
|
||||||
/// Element segments, if any
|
/// Element segments, if any
|
||||||
pub elements: Vec<TableEntryDefinition>,
|
pub elements: Vec<TableEntryDefinition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Table elements entry definition
|
/// Table elements entry definition
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TableEntryDefinition {
|
pub struct TableEntryDefinition {
|
||||||
/// Offset initialization expression
|
/// Offset initialization expression
|
||||||
pub offset: elements::InitExpr,
|
pub offset: elements::InitExpr,
|
||||||
/// Values of initialization
|
/// Values of initialization
|
||||||
pub values: Vec<u32>,
|
pub values: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Table builder
|
/// Table builder
|
||||||
pub struct TableBuilder<F=Identity> {
|
pub struct TableBuilder<F=Identity> {
|
||||||
callback: F,
|
callback: F,
|
||||||
table: TableDefinition,
|
table: TableDefinition,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableBuilder {
|
impl TableBuilder {
|
||||||
/// New table builder
|
/// New table builder
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
TableBuilder::with_callback(Identity)
|
TableBuilder::with_callback(Identity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> TableBuilder<F> where F: Invoke<TableDefinition> {
|
impl<F> TableBuilder<F> where F: Invoke<TableDefinition> {
|
||||||
/// New table builder with callback in chained context
|
/// New table builder with callback in chained context
|
||||||
pub fn with_callback(callback: F) -> Self {
|
pub fn with_callback(callback: F) -> Self {
|
||||||
TableBuilder {
|
TableBuilder {
|
||||||
callback: callback,
|
callback: callback,
|
||||||
table: Default::default(),
|
table: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set/override minimum length
|
/// Set/override minimum length
|
||||||
pub fn with_min(mut self, min: u32) -> Self {
|
pub fn with_min(mut self, min: u32) -> Self {
|
||||||
self.table.min = min;
|
self.table.min = min;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set/override maximum length
|
/// Set/override maximum length
|
||||||
pub fn with_max(mut self, max: Option<u32>) -> Self {
|
pub fn with_max(mut self, max: Option<u32>) -> Self {
|
||||||
self.table.max = max;
|
self.table.max = max;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate initialization expression and element values on specified index
|
/// Generate initialization expression and element values on specified index
|
||||||
pub fn with_element(mut self, index: u32, values: Vec<u32>) -> Self {
|
pub fn with_element(mut self, index: u32, values: Vec<u32>) -> Self {
|
||||||
self.table.elements.push(TableEntryDefinition {
|
self.table.elements.push(TableEntryDefinition {
|
||||||
offset: elements::InitExpr::new(vec![
|
offset: elements::InitExpr::new(vec![
|
||||||
elements::Opcode::I32Const(index as i32),
|
elements::Opcode::I32Const(index as i32),
|
||||||
elements::Opcode::End,
|
elements::Opcode::End,
|
||||||
]),
|
]),
|
||||||
values: values,
|
values: values,
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finalize current builder spawning resulting struct
|
/// Finalize current builder spawning resulting struct
|
||||||
pub fn build(self) -> F::Result {
|
pub fn build(self) -> F::Result {
|
||||||
self.callback.invoke(self.table)
|
self.callback.invoke(self.table)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TableDefinition {
|
impl Default for TableDefinition {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
TableDefinition {
|
TableDefinition {
|
||||||
min: 0,
|
min: 0,
|
||||||
max: None,
|
max: None,
|
||||||
elements: Vec::new(),
|
elements: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,98 +4,98 @@ use super::{Deserialize, Serialize, Error, VarUint7, VarUint32};
|
|||||||
/// Internal reference of the exported entry.
|
/// Internal reference of the exported entry.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Internal {
|
pub enum Internal {
|
||||||
/// Function reference.
|
/// Function reference.
|
||||||
Function(u32),
|
Function(u32),
|
||||||
/// Table reference.
|
/// Table reference.
|
||||||
Table(u32),
|
Table(u32),
|
||||||
/// Memory reference.
|
/// Memory reference.
|
||||||
Memory(u32),
|
Memory(u32),
|
||||||
/// Global reference.
|
/// Global reference.
|
||||||
Global(u32),
|
Global(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for Internal {
|
impl Deserialize for Internal {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let kind = VarUint7::deserialize(reader)?;
|
let kind = VarUint7::deserialize(reader)?;
|
||||||
match kind.into() {
|
match kind.into() {
|
||||||
0x00 => Ok(Internal::Function(VarUint32::deserialize(reader)?.into())),
|
0x00 => Ok(Internal::Function(VarUint32::deserialize(reader)?.into())),
|
||||||
0x01 => Ok(Internal::Table(VarUint32::deserialize(reader)?.into())),
|
0x01 => Ok(Internal::Table(VarUint32::deserialize(reader)?.into())),
|
||||||
0x02 => Ok(Internal::Memory(VarUint32::deserialize(reader)?.into())),
|
0x02 => Ok(Internal::Memory(VarUint32::deserialize(reader)?.into())),
|
||||||
0x03 => Ok(Internal::Global(VarUint32::deserialize(reader)?.into())),
|
0x03 => Ok(Internal::Global(VarUint32::deserialize(reader)?.into())),
|
||||||
_ => Err(Error::UnknownInternalKind(kind.into())),
|
_ => Err(Error::UnknownInternalKind(kind.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Internal {
|
impl Serialize for Internal {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
let (bt, arg) = match self {
|
let (bt, arg) = match self {
|
||||||
Internal::Function(arg) => (0x00, arg),
|
Internal::Function(arg) => (0x00, arg),
|
||||||
Internal::Table(arg) => (0x01, arg),
|
Internal::Table(arg) => (0x01, arg),
|
||||||
Internal::Memory(arg) => (0x02, arg),
|
Internal::Memory(arg) => (0x02, arg),
|
||||||
Internal::Global(arg) => (0x03, arg),
|
Internal::Global(arg) => (0x03, arg),
|
||||||
};
|
};
|
||||||
|
|
||||||
VarUint7::from(bt).serialize(writer)?;
|
VarUint7::from(bt).serialize(writer)?;
|
||||||
VarUint32::from(arg).serialize(writer)?;
|
VarUint32::from(arg).serialize(writer)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Export entry.
|
/// Export entry.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ExportEntry {
|
pub struct ExportEntry {
|
||||||
field_str: String,
|
field_str: String,
|
||||||
internal: Internal,
|
internal: Internal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExportEntry {
|
impl ExportEntry {
|
||||||
/// New export entry
|
/// New export entry
|
||||||
pub fn new(field: String, internal: Internal) -> Self {
|
pub fn new(field: String, internal: Internal) -> Self {
|
||||||
ExportEntry {
|
ExportEntry {
|
||||||
field_str: field,
|
field_str: field,
|
||||||
internal: internal
|
internal: internal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Public name
|
/// Public name
|
||||||
pub fn field(&self) -> &str { &self.field_str }
|
pub fn field(&self) -> &str { &self.field_str }
|
||||||
|
|
||||||
/// Public name (mutable)
|
/// Public name (mutable)
|
||||||
pub fn field_mut(&mut self) -> &mut String { &mut self.field_str }
|
pub fn field_mut(&mut self) -> &mut String { &mut self.field_str }
|
||||||
|
|
||||||
/// Internal reference of the export entry.
|
/// Internal reference of the export entry.
|
||||||
pub fn internal(&self) -> &Internal { &self.internal }
|
pub fn internal(&self) -> &Internal { &self.internal }
|
||||||
|
|
||||||
/// Internal reference of the export entry (mutable).
|
/// Internal reference of the export entry (mutable).
|
||||||
pub fn internal_mut(&mut self) -> &mut Internal { &mut self.internal }
|
pub fn internal_mut(&mut self) -> &mut Internal { &mut self.internal }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for ExportEntry {
|
impl Deserialize for ExportEntry {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let field_str = String::deserialize(reader)?;
|
let field_str = String::deserialize(reader)?;
|
||||||
let internal = Internal::deserialize(reader)?;
|
let internal = Internal::deserialize(reader)?;
|
||||||
|
|
||||||
Ok(ExportEntry {
|
Ok(ExportEntry {
|
||||||
field_str: field_str,
|
field_str: field_str,
|
||||||
internal: internal,
|
internal: internal,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for ExportEntry {
|
impl Serialize for ExportEntry {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
self.field_str.serialize(writer)?;
|
self.field_str.serialize(writer)?;
|
||||||
self.internal.serialize(writer)?;
|
self.internal.serialize(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use super::{
|
use super::{
|
||||||
Deserialize, Error, ValueType, VarUint32, CountedList, Opcodes,
|
Deserialize, Error, ValueType, VarUint32, CountedList, Opcodes,
|
||||||
Serialize, CountedWriter, CountedListWriter,
|
Serialize, CountedWriter, CountedListWriter,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Function signature (type reference)
|
/// Function signature (type reference)
|
||||||
@ -9,122 +9,122 @@ use super::{
|
|||||||
pub struct Func(u32);
|
pub struct Func(u32);
|
||||||
|
|
||||||
impl Func {
|
impl Func {
|
||||||
/// New function signature
|
/// New function signature
|
||||||
pub fn new(type_ref: u32) -> Self { Func(type_ref) }
|
pub fn new(type_ref: u32) -> Self { Func(type_ref) }
|
||||||
|
|
||||||
/// Function signature type reference.
|
/// Function signature type reference.
|
||||||
pub fn type_ref(&self) -> u32 {
|
pub fn type_ref(&self) -> u32 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function signature type reference (mutable).
|
/// Function signature type reference (mutable).
|
||||||
pub fn type_ref_mut(&mut self) -> &mut u32 {
|
pub fn type_ref_mut(&mut self) -> &mut u32 {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Local definition inside the function body.
|
/// Local definition inside the function body.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Local {
|
pub struct Local {
|
||||||
count: u32,
|
count: u32,
|
||||||
value_type: ValueType,
|
value_type: ValueType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Local {
|
impl Local {
|
||||||
/// New local with `count` and `value_type`.
|
/// New local with `count` and `value_type`.
|
||||||
pub fn new(count: u32, value_type: ValueType) -> Self {
|
pub fn new(count: u32, value_type: ValueType) -> Self {
|
||||||
Local { count: count, value_type: value_type }
|
Local { count: count, value_type: value_type }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of locals with the shared type.
|
/// Number of locals with the shared type.
|
||||||
pub fn count(&self) -> u32 { self.count }
|
pub fn count(&self) -> u32 { self.count }
|
||||||
|
|
||||||
/// Type of the locals.
|
/// Type of the locals.
|
||||||
pub fn value_type(&self) -> ValueType { self.value_type }
|
pub fn value_type(&self) -> ValueType { self.value_type }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for Local {
|
impl Deserialize for Local {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let count = VarUint32::deserialize(reader)?;
|
let count = VarUint32::deserialize(reader)?;
|
||||||
let value_type = ValueType::deserialize(reader)?;
|
let value_type = ValueType::deserialize(reader)?;
|
||||||
Ok(Local { count: count.into(), value_type: value_type })
|
Ok(Local { count: count.into(), value_type: value_type })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Local {
|
impl Serialize for Local {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
VarUint32::from(self.count).serialize(writer)?;
|
VarUint32::from(self.count).serialize(writer)?;
|
||||||
self.value_type.serialize(writer)?;
|
self.value_type.serialize(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function body definition.
|
/// Function body definition.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FuncBody {
|
pub struct FuncBody {
|
||||||
locals: Vec<Local>,
|
locals: Vec<Local>,
|
||||||
opcodes: Opcodes,
|
opcodes: Opcodes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncBody {
|
impl FuncBody {
|
||||||
/// New function body with given `locals` and `opcodes`
|
/// New function body with given `locals` and `opcodes`
|
||||||
pub fn new(locals: Vec<Local>, opcodes: Opcodes) -> Self {
|
pub fn new(locals: Vec<Local>, opcodes: Opcodes) -> Self {
|
||||||
FuncBody { locals: locals, opcodes: opcodes }
|
FuncBody { locals: locals, opcodes: opcodes }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List of individual opcodes
|
/// List of individual opcodes
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
FuncBody { locals: Vec::new(), opcodes: Opcodes::empty() }
|
FuncBody { locals: Vec::new(), opcodes: Opcodes::empty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locals declared in function body.
|
/// Locals declared in function body.
|
||||||
pub fn locals(&self) -> &[Local] { &self.locals }
|
pub fn locals(&self) -> &[Local] { &self.locals }
|
||||||
|
|
||||||
/// Opcode sequence of the function body. Minimal opcode sequence
|
/// Opcode sequence of the function body. Minimal opcode sequence
|
||||||
/// is just `&[Opcode::End]`
|
/// is just `&[Opcode::End]`
|
||||||
pub fn code(&self) -> &Opcodes { &self.opcodes }
|
pub fn code(&self) -> &Opcodes { &self.opcodes }
|
||||||
|
|
||||||
/// Locals declared in function body (mutable).
|
/// Locals declared in function body (mutable).
|
||||||
pub fn locals_mut(&mut self) -> &mut Vec<Local> { &mut self.locals }
|
pub fn locals_mut(&mut self) -> &mut Vec<Local> { &mut self.locals }
|
||||||
|
|
||||||
/// Opcode sequence of the function body (mutable).
|
/// Opcode sequence of the function body (mutable).
|
||||||
pub fn code_mut(&mut self) -> &mut Opcodes { &mut self.opcodes }
|
pub fn code_mut(&mut self) -> &mut Opcodes { &mut self.opcodes }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for FuncBody {
|
impl Deserialize for FuncBody {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
// todo: maybe use reader.take(section_length)
|
// todo: maybe use reader.take(section_length)
|
||||||
let _body_size = VarUint32::deserialize(reader)?;
|
let _body_size = VarUint32::deserialize(reader)?;
|
||||||
let locals: Vec<Local> = CountedList::deserialize(reader)?.into_inner();
|
let locals: Vec<Local> = CountedList::deserialize(reader)?.into_inner();
|
||||||
let opcodes = Opcodes::deserialize(reader)?;
|
let opcodes = Opcodes::deserialize(reader)?;
|
||||||
Ok(FuncBody { locals: locals, opcodes: opcodes })
|
Ok(FuncBody { locals: locals, opcodes: opcodes })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for FuncBody {
|
impl Serialize for FuncBody {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
let mut counted_writer = CountedWriter::new(writer);
|
let mut counted_writer = CountedWriter::new(writer);
|
||||||
|
|
||||||
let data = self.locals;
|
let data = self.locals;
|
||||||
let counted_list = CountedListWriter::<Local, _>(
|
let counted_list = CountedListWriter::<Local, _>(
|
||||||
data.len(),
|
data.len(),
|
||||||
data.into_iter().map(Into::into),
|
data.into_iter().map(Into::into),
|
||||||
);
|
);
|
||||||
counted_list.serialize(&mut counted_writer)?;
|
counted_list.serialize(&mut counted_writer)?;
|
||||||
|
|
||||||
let code = self.opcodes;
|
let code = self.opcodes;
|
||||||
code.serialize(&mut counted_writer)?;
|
code.serialize(&mut counted_writer)?;
|
||||||
|
|
||||||
counted_writer.done()?;
|
counted_writer.done()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,47 +4,47 @@ use super::{Deserialize, Serialize, Error, GlobalType, InitExpr};
|
|||||||
/// Global entry in the module.
|
/// Global entry in the module.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GlobalEntry {
|
pub struct GlobalEntry {
|
||||||
global_type: GlobalType,
|
global_type: GlobalType,
|
||||||
init_expr: InitExpr,
|
init_expr: InitExpr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalEntry {
|
impl GlobalEntry {
|
||||||
/// New global entry
|
/// New global entry
|
||||||
pub fn new(global_type: GlobalType, init_expr: InitExpr) -> Self {
|
pub fn new(global_type: GlobalType, init_expr: InitExpr) -> Self {
|
||||||
GlobalEntry {
|
GlobalEntry {
|
||||||
global_type: global_type,
|
global_type: global_type,
|
||||||
init_expr: init_expr,
|
init_expr: init_expr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Global type.
|
/// Global type.
|
||||||
pub fn global_type(&self) -> &GlobalType { &self.global_type }
|
pub fn global_type(&self) -> &GlobalType { &self.global_type }
|
||||||
/// Initialization expression (opcodes) for global.
|
/// Initialization expression (opcodes) for global.
|
||||||
pub fn init_expr(&self) -> &InitExpr { &self.init_expr }
|
pub fn init_expr(&self) -> &InitExpr { &self.init_expr }
|
||||||
/// Global type (mutable)
|
/// Global type (mutable)
|
||||||
pub fn global_type_mut(&mut self) -> &mut GlobalType { &mut self.global_type }
|
pub fn global_type_mut(&mut self) -> &mut GlobalType { &mut self.global_type }
|
||||||
/// Initialization expression (opcodes) for global (mutable)
|
/// Initialization expression (opcodes) for global (mutable)
|
||||||
pub fn init_expr_mut(&mut self) -> &mut InitExpr { &mut self.init_expr }
|
pub fn init_expr_mut(&mut self) -> &mut InitExpr { &mut self.init_expr }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for GlobalEntry {
|
impl Deserialize for GlobalEntry {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let global_type = GlobalType::deserialize(reader)?;
|
let global_type = GlobalType::deserialize(reader)?;
|
||||||
let init_expr = InitExpr::deserialize(reader)?;
|
let init_expr = InitExpr::deserialize(reader)?;
|
||||||
|
|
||||||
Ok(GlobalEntry {
|
Ok(GlobalEntry {
|
||||||
global_type: global_type,
|
global_type: global_type,
|
||||||
init_expr: init_expr,
|
init_expr: init_expr,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for GlobalEntry {
|
impl Serialize for GlobalEntry {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
self.global_type.serialize(writer)?;
|
self.global_type.serialize(writer)?;
|
||||||
self.init_expr.serialize(writer)
|
self.init_expr.serialize(writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,152 +1,152 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use super::{
|
use super::{
|
||||||
Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1,
|
Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint32, VarUint1,
|
||||||
ValueType, TableElementType
|
ValueType, TableElementType
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Global definition struct
|
/// Global definition struct
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct GlobalType {
|
pub struct GlobalType {
|
||||||
content_type: ValueType,
|
content_type: ValueType,
|
||||||
is_mutable: bool,
|
is_mutable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlobalType {
|
impl GlobalType {
|
||||||
/// New global type
|
/// New global type
|
||||||
pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
|
pub fn new(content_type: ValueType, is_mutable: bool) -> Self {
|
||||||
GlobalType {
|
GlobalType {
|
||||||
content_type: content_type,
|
content_type: content_type,
|
||||||
is_mutable: is_mutable,
|
is_mutable: is_mutable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type of the global entry
|
/// Type of the global entry
|
||||||
pub fn content_type(&self) -> ValueType { self.content_type }
|
pub fn content_type(&self) -> ValueType { self.content_type }
|
||||||
|
|
||||||
/// Is global entry is declared as mutable
|
/// Is global entry is declared as mutable
|
||||||
pub fn is_mutable(&self) -> bool { self.is_mutable }
|
pub fn is_mutable(&self) -> bool { self.is_mutable }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for GlobalType {
|
impl Deserialize for GlobalType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let content_type = ValueType::deserialize(reader)?;
|
let content_type = ValueType::deserialize(reader)?;
|
||||||
let is_mutable = VarUint1::deserialize(reader)?;
|
let is_mutable = VarUint1::deserialize(reader)?;
|
||||||
Ok(GlobalType {
|
Ok(GlobalType {
|
||||||
content_type: content_type,
|
content_type: content_type,
|
||||||
is_mutable: is_mutable.into(),
|
is_mutable: is_mutable.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for GlobalType {
|
impl Serialize for GlobalType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
self.content_type.serialize(writer)?;
|
self.content_type.serialize(writer)?;
|
||||||
VarUint1::from(self.is_mutable).serialize(writer)?;
|
VarUint1::from(self.is_mutable).serialize(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Table entry
|
/// Table entry
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct TableType {
|
pub struct TableType {
|
||||||
elem_type: TableElementType,
|
elem_type: TableElementType,
|
||||||
limits: ResizableLimits,
|
limits: ResizableLimits,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableType {
|
impl TableType {
|
||||||
/// New table definition
|
/// New table definition
|
||||||
pub fn new(min: u32, max: Option<u32>) -> Self {
|
pub fn new(min: u32, max: Option<u32>) -> Self {
|
||||||
TableType {
|
TableType {
|
||||||
elem_type: TableElementType::AnyFunc,
|
elem_type: TableElementType::AnyFunc,
|
||||||
limits: ResizableLimits::new(min, max),
|
limits: ResizableLimits::new(min, max),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Table memory specification
|
/// Table memory specification
|
||||||
pub fn limits(&self) -> &ResizableLimits { &self.limits }
|
pub fn limits(&self) -> &ResizableLimits { &self.limits }
|
||||||
|
|
||||||
/// Table element type
|
/// Table element type
|
||||||
pub fn elem_type(&self) -> TableElementType { self.elem_type }
|
pub fn elem_type(&self) -> TableElementType { self.elem_type }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for TableType {
|
impl Deserialize for TableType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let elem_type = TableElementType::deserialize(reader)?;
|
let elem_type = TableElementType::deserialize(reader)?;
|
||||||
let limits = ResizableLimits::deserialize(reader)?;
|
let limits = ResizableLimits::deserialize(reader)?;
|
||||||
Ok(TableType {
|
Ok(TableType {
|
||||||
elem_type: elem_type,
|
elem_type: elem_type,
|
||||||
limits: limits,
|
limits: limits,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for TableType {
|
impl Serialize for TableType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
self.elem_type.serialize(writer)?;
|
self.elem_type.serialize(writer)?;
|
||||||
self.limits.serialize(writer)
|
self.limits.serialize(writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Memory limits
|
/// Memory limits
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct ResizableLimits {
|
pub struct ResizableLimits {
|
||||||
initial: u32,
|
initial: u32,
|
||||||
maximum: Option<u32>,
|
maximum: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResizableLimits {
|
impl ResizableLimits {
|
||||||
/// New memory limits definition
|
/// New memory limits definition
|
||||||
pub fn new(min: u32, max: Option<u32>) -> Self {
|
pub fn new(min: u32, max: Option<u32>) -> Self {
|
||||||
ResizableLimits {
|
ResizableLimits {
|
||||||
initial: min,
|
initial: min,
|
||||||
maximum: max,
|
maximum: max,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Initial size
|
/// Initial size
|
||||||
pub fn initial(&self) -> u32 { self.initial }
|
pub fn initial(&self) -> u32 { self.initial }
|
||||||
/// Maximum size
|
/// Maximum size
|
||||||
pub fn maximum(&self) -> Option<u32> { self.maximum }
|
pub fn maximum(&self) -> Option<u32> { self.maximum }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for ResizableLimits {
|
impl Deserialize for ResizableLimits {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let has_max = VarUint1::deserialize(reader)?;
|
let has_max = VarUint1::deserialize(reader)?;
|
||||||
let initial = VarUint32::deserialize(reader)?;
|
let initial = VarUint32::deserialize(reader)?;
|
||||||
let maximum = if has_max.into() {
|
let maximum = if has_max.into() {
|
||||||
Some(VarUint32::deserialize(reader)?.into())
|
Some(VarUint32::deserialize(reader)?.into())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ResizableLimits {
|
Ok(ResizableLimits {
|
||||||
initial: initial.into(),
|
initial: initial.into(),
|
||||||
maximum: maximum,
|
maximum: maximum,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for ResizableLimits {
|
impl Serialize for ResizableLimits {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
let max = self.maximum;
|
let max = self.maximum;
|
||||||
VarUint1::from(max.is_some()).serialize(writer)?;
|
VarUint1::from(max.is_some()).serialize(writer)?;
|
||||||
VarUint32::from(self.initial).serialize(writer)?;
|
VarUint32::from(self.initial).serialize(writer)?;
|
||||||
if let Some(val) = max {
|
if let Some(val) = max {
|
||||||
VarUint32::from(val).serialize(writer)?;
|
VarUint32::from(val).serialize(writer)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Memory entry.
|
/// Memory entry.
|
||||||
@ -154,152 +154,152 @@ impl Serialize for ResizableLimits {
|
|||||||
pub struct MemoryType(ResizableLimits);
|
pub struct MemoryType(ResizableLimits);
|
||||||
|
|
||||||
impl MemoryType {
|
impl MemoryType {
|
||||||
/// New memory definition
|
/// New memory definition
|
||||||
pub fn new(min: u32, max: Option<u32>) -> Self {
|
pub fn new(min: u32, max: Option<u32>) -> Self {
|
||||||
MemoryType(ResizableLimits::new(min, max))
|
MemoryType(ResizableLimits::new(min, max))
|
||||||
}
|
}
|
||||||
/// Limits of the memory entry.
|
/// Limits of the memory entry.
|
||||||
pub fn limits(&self) -> &ResizableLimits {
|
pub fn limits(&self) -> &ResizableLimits {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for MemoryType {
|
impl Deserialize for MemoryType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
Ok(MemoryType(ResizableLimits::deserialize(reader)?))
|
Ok(MemoryType(ResizableLimits::deserialize(reader)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for MemoryType {
|
impl Serialize for MemoryType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
self.0.serialize(writer)
|
self.0.serialize(writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// External to local binding.
|
/// External to local binding.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum External {
|
pub enum External {
|
||||||
/// Binds to function with index.
|
/// Binds to function with index.
|
||||||
Function(u32),
|
Function(u32),
|
||||||
/// Describes local table definition to be imported as.
|
/// Describes local table definition to be imported as.
|
||||||
Table(TableType),
|
Table(TableType),
|
||||||
/// Describes local memory definition to be imported as.
|
/// Describes local memory definition to be imported as.
|
||||||
Memory(MemoryType),
|
Memory(MemoryType),
|
||||||
/// Describes local global entry to be imported as.
|
/// Describes local global entry to be imported as.
|
||||||
Global(GlobalType),
|
Global(GlobalType),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for External {
|
impl Deserialize for External {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let kind = VarUint7::deserialize(reader)?;
|
let kind = VarUint7::deserialize(reader)?;
|
||||||
match kind.into() {
|
match kind.into() {
|
||||||
0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
|
0x00 => Ok(External::Function(VarUint32::deserialize(reader)?.into())),
|
||||||
0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
|
0x01 => Ok(External::Table(TableType::deserialize(reader)?)),
|
||||||
0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
|
0x02 => Ok(External::Memory(MemoryType::deserialize(reader)?)),
|
||||||
0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
|
0x03 => Ok(External::Global(GlobalType::deserialize(reader)?)),
|
||||||
_ => Err(Error::UnknownExternalKind(kind.into())),
|
_ => Err(Error::UnknownExternalKind(kind.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for External {
|
impl Serialize for External {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
use self::External::*;
|
use self::External::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Function(index) => {
|
Function(index) => {
|
||||||
VarUint7::from(0x00).serialize(writer)?;
|
VarUint7::from(0x00).serialize(writer)?;
|
||||||
VarUint32::from(index).serialize(writer)?;
|
VarUint32::from(index).serialize(writer)?;
|
||||||
},
|
},
|
||||||
Table(tt) => {
|
Table(tt) => {
|
||||||
VarInt7::from(0x01).serialize(writer)?;
|
VarInt7::from(0x01).serialize(writer)?;
|
||||||
tt.serialize(writer)?;
|
tt.serialize(writer)?;
|
||||||
},
|
},
|
||||||
Memory(mt) => {
|
Memory(mt) => {
|
||||||
VarInt7::from(0x02).serialize(writer)?;
|
VarInt7::from(0x02).serialize(writer)?;
|
||||||
mt.serialize(writer)?;
|
mt.serialize(writer)?;
|
||||||
},
|
},
|
||||||
Global(gt) => {
|
Global(gt) => {
|
||||||
VarInt7::from(0x03).serialize(writer)?;
|
VarInt7::from(0x03).serialize(writer)?;
|
||||||
gt.serialize(writer)?;
|
gt.serialize(writer)?;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Import entry.
|
/// Import entry.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ImportEntry {
|
pub struct ImportEntry {
|
||||||
module_str: String,
|
module_str: String,
|
||||||
field_str: String,
|
field_str: String,
|
||||||
external: External,
|
external: External,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImportEntry {
|
impl ImportEntry {
|
||||||
/// New import entry.
|
/// New import entry.
|
||||||
pub fn new(module_str: String, field_str: String, external: External) -> Self {
|
pub fn new(module_str: String, field_str: String, external: External) -> Self {
|
||||||
ImportEntry {
|
ImportEntry {
|
||||||
module_str: module_str,
|
module_str: module_str,
|
||||||
field_str: field_str,
|
field_str: field_str,
|
||||||
external: external,
|
external: external,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Module reference of the import entry.
|
/// Module reference of the import entry.
|
||||||
pub fn module(&self) -> &str { &self.module_str }
|
pub fn module(&self) -> &str { &self.module_str }
|
||||||
|
|
||||||
/// Module reference of the import entry (mutable).
|
/// Module reference of the import entry (mutable).
|
||||||
pub fn module_mut(&mut self) -> &mut String {
|
pub fn module_mut(&mut self) -> &mut String {
|
||||||
&mut self.module_str
|
&mut self.module_str
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Field reference of the import entry.
|
/// Field reference of the import entry.
|
||||||
pub fn field(&self) -> &str { &self.field_str }
|
pub fn field(&self) -> &str { &self.field_str }
|
||||||
|
|
||||||
/// Field reference of the import entry (mutable)
|
/// Field reference of the import entry (mutable)
|
||||||
pub fn field_mut(&mut self) -> &mut String {
|
pub fn field_mut(&mut self) -> &mut String {
|
||||||
&mut self.field_str
|
&mut self.field_str
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Local binidng of the import entry.
|
/// Local binidng of the import entry.
|
||||||
pub fn external(&self) -> &External { &self.external }
|
pub fn external(&self) -> &External { &self.external }
|
||||||
|
|
||||||
/// Local binidng of the import entry (mutable)
|
/// Local binidng of the import entry (mutable)
|
||||||
pub fn external_mut(&mut self) -> &mut External { &mut self.external }
|
pub fn external_mut(&mut self) -> &mut External { &mut self.external }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for ImportEntry {
|
impl Deserialize for ImportEntry {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let module_str = String::deserialize(reader)?;
|
let module_str = String::deserialize(reader)?;
|
||||||
let field_str = String::deserialize(reader)?;
|
let field_str = String::deserialize(reader)?;
|
||||||
let external = External::deserialize(reader)?;
|
let external = External::deserialize(reader)?;
|
||||||
|
|
||||||
Ok(ImportEntry {
|
Ok(ImportEntry {
|
||||||
module_str: module_str,
|
module_str: module_str,
|
||||||
field_str: field_str,
|
field_str: field_str,
|
||||||
external: external,
|
external: external,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for ImportEntry {
|
impl Serialize for ImportEntry {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
self.module_str.serialize(writer)?;
|
self.module_str.serialize(writer)?;
|
||||||
self.field_str.serialize(writer)?;
|
self.field_str.serialize(writer)?;
|
||||||
self.external.serialize(writer)
|
self.external.serialize(writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -19,16 +19,16 @@ mod name_section;
|
|||||||
|
|
||||||
pub use self::module::{Module, peek_size, ImportCountType};
|
pub use self::module::{Module, peek_size, ImportCountType};
|
||||||
pub use self::section::{
|
pub use self::section::{
|
||||||
Section, FunctionSection, CodeSection, MemorySection, DataSection,
|
Section, FunctionSection, CodeSection, MemorySection, DataSection,
|
||||||
ImportSection, ExportSection, GlobalSection, TypeSection, ElementSection,
|
ImportSection, ExportSection, GlobalSection, TypeSection, ElementSection,
|
||||||
TableSection, CustomSection,
|
TableSection, CustomSection,
|
||||||
};
|
};
|
||||||
pub use self::import_entry::{ImportEntry, ResizableLimits, MemoryType, TableType, GlobalType, External};
|
pub use self::import_entry::{ImportEntry, ResizableLimits, MemoryType, TableType, GlobalType, External};
|
||||||
pub use self::export_entry::{ExportEntry, Internal};
|
pub use self::export_entry::{ExportEntry, Internal};
|
||||||
pub use self::global_entry::GlobalEntry;
|
pub use self::global_entry::GlobalEntry;
|
||||||
pub use self::primitives::{
|
pub use self::primitives::{
|
||||||
VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64,
|
VarUint32, VarUint7, Uint8, VarUint1, VarInt7, Uint32, VarInt32, VarInt64,
|
||||||
Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter,
|
Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter,
|
||||||
};
|
};
|
||||||
pub use self::types::{Type, ValueType, BlockType, FunctionType, TableElementType};
|
pub use self::types::{Type, ValueType, BlockType, FunctionType, TableElementType};
|
||||||
pub use self::ops::{Opcode, Opcodes, InitExpr};
|
pub use self::ops::{Opcode, Opcodes, InitExpr};
|
||||||
@ -36,164 +36,164 @@ pub use self::func::{Func, FuncBody, Local};
|
|||||||
pub use self::segment::{ElementSegment, DataSegment};
|
pub use self::segment::{ElementSegment, DataSegment};
|
||||||
pub use self::index_map::IndexMap;
|
pub use self::index_map::IndexMap;
|
||||||
pub use self::name_section::{
|
pub use self::name_section::{
|
||||||
NameMap, NameSection, ModuleNameSection, FunctionNameSection,
|
NameMap, NameSection, ModuleNameSection, FunctionNameSection,
|
||||||
LocalNameSection,
|
LocalNameSection,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Deserialization from serial i/o
|
/// Deserialization from serial i/o
|
||||||
pub trait Deserialize : Sized {
|
pub trait Deserialize : Sized {
|
||||||
/// Serialization error produced by deserialization routine.
|
/// Serialization error produced by deserialization routine.
|
||||||
type Error;
|
type Error;
|
||||||
/// Deserialize type from serial i/o
|
/// Deserialize type from serial i/o
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialization to serial i/o
|
/// Serialization to serial i/o
|
||||||
pub trait Serialize {
|
pub trait Serialize {
|
||||||
/// Serialization error produced by serialization routine.
|
/// Serialization error produced by serialization routine.
|
||||||
type Error;
|
type Error;
|
||||||
/// Serialize type to serial i/o
|
/// Serialize type to serial i/o
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialization/serialization error
|
/// Deserialization/serialization error
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Unexpected end of input
|
/// Unexpected end of input
|
||||||
UnexpectedEof,
|
UnexpectedEof,
|
||||||
/// Invalid magic
|
/// Invalid magic
|
||||||
InvalidMagic,
|
InvalidMagic,
|
||||||
/// Unsupported version
|
/// Unsupported version
|
||||||
UnsupportedVersion(u32),
|
UnsupportedVersion(u32),
|
||||||
/// Inconsistence between declared and actual length
|
/// Inconsistence between declared and actual length
|
||||||
InconsistentLength {
|
InconsistentLength {
|
||||||
/// Expected length of the definition
|
/// Expected length of the definition
|
||||||
expected: usize,
|
expected: usize,
|
||||||
/// Actual length of the definition
|
/// Actual length of the definition
|
||||||
actual: usize
|
actual: usize
|
||||||
},
|
},
|
||||||
/// Other static error
|
/// Other static error
|
||||||
Other(&'static str),
|
Other(&'static str),
|
||||||
/// Other allocated error
|
/// Other allocated error
|
||||||
HeapOther(String),
|
HeapOther(String),
|
||||||
/// Invalid/unknown value type declaration
|
/// Invalid/unknown value type declaration
|
||||||
UnknownValueType(i8),
|
UnknownValueType(i8),
|
||||||
/// Invalid/unknown table element type declaration
|
/// Invalid/unknown table element type declaration
|
||||||
UnknownTableElementType(i8),
|
UnknownTableElementType(i8),
|
||||||
/// Non-utf8 string
|
/// Non-utf8 string
|
||||||
NonUtf8String,
|
NonUtf8String,
|
||||||
/// Unknown external kind code
|
/// Unknown external kind code
|
||||||
UnknownExternalKind(u8),
|
UnknownExternalKind(u8),
|
||||||
/// Unknown internal kind code
|
/// Unknown internal kind code
|
||||||
UnknownInternalKind(u8),
|
UnknownInternalKind(u8),
|
||||||
/// Unknown opcode encountered
|
/// Unknown opcode encountered
|
||||||
UnknownOpcode(u8),
|
UnknownOpcode(u8),
|
||||||
/// Invalid VarUint1 value
|
/// Invalid VarUint1 value
|
||||||
InvalidVarUint1(u8),
|
InvalidVarUint1(u8),
|
||||||
/// Invalid VarInt32 value
|
/// Invalid VarInt32 value
|
||||||
InvalidVarInt32,
|
InvalidVarInt32,
|
||||||
/// Invalid VarInt64 value
|
/// Invalid VarInt64 value
|
||||||
InvalidVarInt64,
|
InvalidVarInt64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Error::UnexpectedEof => write!(f, "Unexpected end of input"),
|
Error::UnexpectedEof => write!(f, "Unexpected end of input"),
|
||||||
Error::InvalidMagic => write!(f, "Invalid magic number at start of file"),
|
Error::InvalidMagic => write!(f, "Invalid magic number at start of file"),
|
||||||
Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v),
|
Error::UnsupportedVersion(v) => write!(f, "Unsupported wasm version {}", v),
|
||||||
Error::InconsistentLength { expected, actual } => {
|
Error::InconsistentLength { expected, actual } => {
|
||||||
write!(f, "Expected length {}, found {}", expected, actual)
|
write!(f, "Expected length {}, found {}", expected, actual)
|
||||||
}
|
}
|
||||||
Error::Other(msg) => write!(f, "{}", msg),
|
Error::Other(msg) => write!(f, "{}", msg),
|
||||||
Error::HeapOther(ref msg) => write!(f, "{}", msg),
|
Error::HeapOther(ref msg) => write!(f, "{}", msg),
|
||||||
Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty),
|
Error::UnknownValueType(ty) => write!(f, "Invalid or unknown value type {}", ty),
|
||||||
Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty),
|
Error::UnknownTableElementType(ty) => write!(f, "Unknown table element type {}", ty),
|
||||||
Error::NonUtf8String => write!(f, "Non-UTF-8 string"),
|
Error::NonUtf8String => write!(f, "Non-UTF-8 string"),
|
||||||
Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind),
|
Error::UnknownExternalKind(kind) => write!(f, "Unknown external kind {}", kind),
|
||||||
Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind),
|
Error::UnknownInternalKind(kind) => write!(f, "Unknown internal kind {}", kind),
|
||||||
Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode),
|
Error::UnknownOpcode(opcode) => write!(f, "Unknown opcode {}", opcode),
|
||||||
Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val),
|
Error::InvalidVarUint1(val) => write!(f, "Not an unsigned 1-bit integer: {}", val),
|
||||||
Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"),
|
Error::InvalidVarInt32 => write!(f, "Not a signed 32-bit integer"),
|
||||||
Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"),
|
Error::InvalidVarInt64 => write!(f, "Not a signed 64-bit integer"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for Error {
|
impl error::Error for Error {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
Error::UnexpectedEof => "Unexpected end of input",
|
Error::UnexpectedEof => "Unexpected end of input",
|
||||||
Error::InvalidMagic => "Invalid magic number at start of file",
|
Error::InvalidMagic => "Invalid magic number at start of file",
|
||||||
Error::UnsupportedVersion(_) => "Unsupported wasm version",
|
Error::UnsupportedVersion(_) => "Unsupported wasm version",
|
||||||
Error::InconsistentLength { .. } => "Inconsistent length",
|
Error::InconsistentLength { .. } => "Inconsistent length",
|
||||||
Error::Other(msg) => msg,
|
Error::Other(msg) => msg,
|
||||||
Error::HeapOther(ref msg) => &msg[..],
|
Error::HeapOther(ref msg) => &msg[..],
|
||||||
Error::UnknownValueType(_) => "Invalid or unknown value type",
|
Error::UnknownValueType(_) => "Invalid or unknown value type",
|
||||||
Error::UnknownTableElementType(_) => "Unknown table element type",
|
Error::UnknownTableElementType(_) => "Unknown table element type",
|
||||||
Error::NonUtf8String => "Non-UTF-8 string",
|
Error::NonUtf8String => "Non-UTF-8 string",
|
||||||
Error::UnknownExternalKind(_) => "Unknown external kind",
|
Error::UnknownExternalKind(_) => "Unknown external kind",
|
||||||
Error::UnknownInternalKind(_) => "Unknown internal kind",
|
Error::UnknownInternalKind(_) => "Unknown internal kind",
|
||||||
Error::UnknownOpcode(_) => "Unknown opcode",
|
Error::UnknownOpcode(_) => "Unknown opcode",
|
||||||
Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer",
|
Error::InvalidVarUint1(_) => "Not an unsigned 1-bit integer",
|
||||||
Error::InvalidVarInt32 => "Not a signed 32-bit integer",
|
Error::InvalidVarInt32 => "Not a signed 32-bit integer",
|
||||||
Error::InvalidVarInt64 => "Not a signed 64-bit integer",
|
Error::InvalidVarInt64 => "Not a signed 64-bit integer",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(err: io::Error) -> Self {
|
fn from(err: io::Error) -> Self {
|
||||||
Error::HeapOther(format!("I/O Error: {}", err))
|
Error::HeapOther(format!("I/O Error: {}", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unparsed part of the module/section
|
/// Unparsed part of the module/section
|
||||||
pub struct Unparsed(pub Vec<u8>);
|
pub struct Unparsed(pub Vec<u8>);
|
||||||
|
|
||||||
impl Deserialize for Unparsed {
|
impl Deserialize for Unparsed {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let len = VarUint32::deserialize(reader)?.into();
|
let len = VarUint32::deserialize(reader)?.into();
|
||||||
let mut vec = vec![0u8; len];
|
let mut vec = vec![0u8; len];
|
||||||
reader.read_exact(&mut vec[..])?;
|
reader.read_exact(&mut vec[..])?;
|
||||||
Ok(Unparsed(vec))
|
Ok(Unparsed(vec))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Unparsed> for Vec<u8> {
|
impl From<Unparsed> for Vec<u8> {
|
||||||
fn from(u: Unparsed) -> Vec<u8> {
|
fn from(u: Unparsed) -> Vec<u8> {
|
||||||
u.0
|
u.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize module from file.
|
/// Deserialize module from file.
|
||||||
pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
|
pub fn deserialize_file<P: AsRef<::std::path::Path>>(p: P) -> Result<Module, Error> {
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
let mut contents = Vec::new();
|
let mut contents = Vec::new();
|
||||||
::std::fs::File::open(p)?.read_to_end(&mut contents)?;
|
::std::fs::File::open(p)?.read_to_end(&mut contents)?;
|
||||||
|
|
||||||
deserialize_buffer(&contents)
|
deserialize_buffer(&contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize deserializable type from buffer.
|
/// Deserialize deserializable type from buffer.
|
||||||
pub fn deserialize_buffer<T: Deserialize>(contents: &[u8]) -> Result<T, T::Error> {
|
pub fn deserialize_buffer<T: Deserialize>(contents: &[u8]) -> Result<T, T::Error> {
|
||||||
let mut reader = io::Cursor::new(contents);
|
let mut reader = io::Cursor::new(contents);
|
||||||
T::deserialize(&mut reader)
|
T::deserialize(&mut reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create buffer with serialized value.
|
/// Create buffer with serialized value.
|
||||||
pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> {
|
pub fn serialize<T: Serialize>(val: T) -> Result<Vec<u8>, T::Error> {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
val.serialize(&mut buf)?;
|
val.serialize(&mut buf)?;
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialize module to the file
|
/// Serialize module to the file
|
||||||
pub fn serialize_to_file<P: AsRef<::std::path::Path>>(p: P, module: Module) -> Result<(), Error>
|
pub fn serialize_to_file<P: AsRef<::std::path::Path>>(p: P, module: Module) -> Result<(), Error>
|
||||||
{
|
{
|
||||||
let mut io = ::std::fs::File::create(p)?;
|
let mut io = ::std::fs::File::create(p)?;
|
||||||
module.serialize(&mut io)
|
module.serialize(&mut io)
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ use byteorder::{LittleEndian, ByteOrder};
|
|||||||
|
|
||||||
use super::{Deserialize, Serialize, Error, Uint32, External};
|
use super::{Deserialize, Serialize, Error, Uint32, External};
|
||||||
use super::section::{
|
use super::section::{
|
||||||
Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection,
|
Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection,
|
||||||
GlobalSection, TableSection, ElementSection, DataSection, MemorySection
|
GlobalSection, TableSection, ElementSection, DataSection, MemorySection
|
||||||
};
|
};
|
||||||
use super::name_section::NameSection;
|
use super::name_section::NameSection;
|
||||||
|
|
||||||
@ -13,494 +13,494 @@ const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6d];
|
|||||||
/// WebAssembly module
|
/// WebAssembly module
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
magic: u32,
|
magic: u32,
|
||||||
version: u32,
|
version: u32,
|
||||||
sections: Vec<Section>,
|
sections: Vec<Section>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
/// Type of the import entry to count
|
/// Type of the import entry to count
|
||||||
pub enum ImportCountType {
|
pub enum ImportCountType {
|
||||||
/// Count functions
|
/// Count functions
|
||||||
Function,
|
Function,
|
||||||
/// Count globals
|
/// Count globals
|
||||||
Global,
|
Global,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Module {
|
impl Default for Module {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Module {
|
Module {
|
||||||
magic: LittleEndian::read_u32(&WASM_MAGIC_NUMBER),
|
magic: LittleEndian::read_u32(&WASM_MAGIC_NUMBER),
|
||||||
version: 1,
|
version: 1,
|
||||||
sections: Vec::with_capacity(16),
|
sections: Vec::with_capacity(16),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
/// New module with sections
|
/// New module with sections
|
||||||
pub fn new(sections: Vec<Section>) -> Self {
|
pub fn new(sections: Vec<Section>) -> Self {
|
||||||
Module {
|
Module {
|
||||||
sections: sections, ..Default::default()
|
sections: sections, ..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Destructure the module, yielding sections
|
/// Destructure the module, yielding sections
|
||||||
pub fn into_sections(self) -> Vec<Section> {
|
pub fn into_sections(self) -> Vec<Section> {
|
||||||
self.sections
|
self.sections
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Version of module.
|
/// Version of module.
|
||||||
pub fn version(&self) -> u32 { self.version }
|
pub fn version(&self) -> u32 { self.version }
|
||||||
|
|
||||||
/// Sections list.
|
/// Sections list.
|
||||||
/// Each known section is optional and may appear at most once.
|
/// Each known section is optional and may appear at most once.
|
||||||
pub fn sections(&self) -> &[Section] {
|
pub fn sections(&self) -> &[Section] {
|
||||||
&self.sections
|
&self.sections
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sections list (mutable)
|
/// Sections list (mutable)
|
||||||
/// Each known section is optional and may appear at most once.
|
/// Each known section is optional and may appear at most once.
|
||||||
pub fn sections_mut(&mut self) -> &mut Vec<Section> {
|
pub fn sections_mut(&mut self) -> &mut Vec<Section> {
|
||||||
&mut self.sections
|
&mut self.sections
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Code section, if any.
|
/// Code section, if any.
|
||||||
pub fn code_section(&self) -> Option<&CodeSection> {
|
pub fn code_section(&self) -> Option<&CodeSection> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Code(ref code_section) = section { return Some(code_section); }
|
if let &Section::Code(ref code_section) = section { return Some(code_section); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Types section, if any.
|
/// Types section, if any.
|
||||||
pub fn type_section(&self) -> Option<&TypeSection> {
|
pub fn type_section(&self) -> Option<&TypeSection> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Type(ref type_section) = section { return Some(type_section); }
|
if let &Section::Type(ref type_section) = section { return Some(type_section); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Imports section, if any.
|
/// Imports section, if any.
|
||||||
pub fn import_section(&self) -> Option<&ImportSection> {
|
pub fn import_section(&self) -> Option<&ImportSection> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Import(ref import_section) = section { return Some(import_section); }
|
if let &Section::Import(ref import_section) = section { return Some(import_section); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Globals section, if any.
|
/// Globals section, if any.
|
||||||
pub fn global_section(&self) -> Option<&GlobalSection> {
|
pub fn global_section(&self) -> Option<&GlobalSection> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Global(ref section) = section { return Some(section); }
|
if let &Section::Global(ref section) = section { return Some(section); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Exports section, if any.
|
/// Exports section, if any.
|
||||||
pub fn export_section(&self) -> Option<&ExportSection> {
|
pub fn export_section(&self) -> Option<&ExportSection> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Export(ref export_section) = section { return Some(export_section); }
|
if let &Section::Export(ref export_section) = section { return Some(export_section); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Table section, if any.
|
/// Table section, if any.
|
||||||
pub fn table_section(&self) -> Option<&TableSection> {
|
pub fn table_section(&self) -> Option<&TableSection> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Table(ref section) = section { return Some(section); }
|
if let &Section::Table(ref section) = section { return Some(section); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data section, if any.
|
/// Data section, if any.
|
||||||
pub fn data_section(&self) -> Option<&DataSection> {
|
pub fn data_section(&self) -> Option<&DataSection> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Data(ref section) = section { return Some(section); }
|
if let &Section::Data(ref section) = section { return Some(section); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Element section, if any.
|
/// Element section, if any.
|
||||||
pub fn elements_section(&self) -> Option<&ElementSection> {
|
pub fn elements_section(&self) -> Option<&ElementSection> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Element(ref section) = section { return Some(section); }
|
if let &Section::Element(ref section) = section { return Some(section); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Memory section, if any.
|
/// Memory section, if any.
|
||||||
pub fn memory_section(&self) -> Option<&MemorySection> {
|
pub fn memory_section(&self) -> Option<&MemorySection> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Memory(ref section) = section { return Some(section); }
|
if let &Section::Memory(ref section) = section { return Some(section); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Functions signatures section, if any.
|
/// Functions signatures section, if any.
|
||||||
pub fn function_section(&self) -> Option<&FunctionSection> {
|
pub fn function_section(&self) -> Option<&FunctionSection> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Function(ref sect) = section { return Some(sect); }
|
if let &Section::Function(ref sect) = section { return Some(sect); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start section, if any.
|
/// Start section, if any.
|
||||||
pub fn start_section(&self) -> Option<u32> {
|
pub fn start_section(&self) -> Option<u32> {
|
||||||
for section in self.sections() {
|
for section in self.sections() {
|
||||||
if let &Section::Start(sect) = section { return Some(sect); }
|
if let &Section::Start(sect) = section { return Some(sect); }
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to parse name section in place
|
/// Try to parse name section in place
|
||||||
/// Corresponding custom section with proper header will convert to name sections
|
/// Corresponding custom section with proper header will convert to name sections
|
||||||
/// If some of them will fail to be decoded, Err variant is returned with the list of
|
/// If some of them will fail to be decoded, Err variant is returned with the list of
|
||||||
/// (index, Error) tuples of failed sections.
|
/// (index, Error) tuples of failed sections.
|
||||||
pub fn parse_names(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> {
|
pub fn parse_names(mut self) -> Result<Self, (Vec<(usize, Error)>, Self)> {
|
||||||
let mut parse_errors = Vec::new();
|
let mut parse_errors = Vec::new();
|
||||||
|
|
||||||
for i in 0..self.sections.len() {
|
for i in 0..self.sections.len() {
|
||||||
if let Some(name_section) = {
|
if let Some(name_section) = {
|
||||||
let section = self.sections.get(i).expect("cannot fail because i in range 0..len; qed");
|
let section = self.sections.get(i).expect("cannot fail because i in range 0..len; qed");
|
||||||
if let Section::Custom(ref custom) = *section {
|
if let Section::Custom(ref custom) = *section {
|
||||||
if custom.name() == "name" {
|
if custom.name() == "name" {
|
||||||
let mut rdr = io::Cursor::new(custom.payload());
|
let mut rdr = io::Cursor::new(custom.payload());
|
||||||
let name_section = match NameSection::deserialize(&self, &mut rdr) {
|
let name_section = match NameSection::deserialize(&self, &mut rdr) {
|
||||||
Ok(ns) => ns,
|
Ok(ns) => ns,
|
||||||
Err(e) => { parse_errors.push((i, e)); continue; }
|
Err(e) => { parse_errors.push((i, e)); continue; }
|
||||||
};
|
};
|
||||||
Some(name_section)
|
Some(name_section)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else { None }
|
} else { None }
|
||||||
} {
|
} {
|
||||||
*self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section);
|
*self.sections.get_mut(i).expect("cannot fail because i in range 0..len; qed") = Section::Name(name_section);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if parse_errors.len() > 0 {
|
if parse_errors.len() > 0 {
|
||||||
Err((parse_errors, self))
|
Err((parse_errors, self))
|
||||||
} else {
|
} else {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Count imports by provided type
|
/// Count imports by provided type
|
||||||
pub fn import_count(&self, count_type: ImportCountType) -> usize {
|
pub fn import_count(&self, count_type: ImportCountType) -> usize {
|
||||||
self.import_section()
|
self.import_section()
|
||||||
.map(|is|
|
.map(|is|
|
||||||
is.entries().iter().filter(|import| match (count_type, *import.external()) {
|
is.entries().iter().filter(|import| match (count_type, *import.external()) {
|
||||||
(ImportCountType::Function, External::Function(_)) => true,
|
(ImportCountType::Function, External::Function(_)) => true,
|
||||||
(ImportCountType::Global, External::Global(_)) => true,
|
(ImportCountType::Global, External::Global(_)) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}).count())
|
}).count())
|
||||||
.unwrap_or(0)
|
.unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query functions space
|
/// Query functions space
|
||||||
pub fn functions_space(&self) -> usize {
|
pub fn functions_space(&self) -> usize {
|
||||||
self.import_count(ImportCountType::Function) +
|
self.import_count(ImportCountType::Function) +
|
||||||
self.function_section().map(|fs| fs.entries().len()).unwrap_or(0)
|
self.function_section().map(|fs| fs.entries().len()).unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query globals space
|
/// Query globals space
|
||||||
pub fn globals_space(&self) -> usize {
|
pub fn globals_space(&self) -> usize {
|
||||||
self.import_count(ImportCountType::Global) +
|
self.import_count(ImportCountType::Global) +
|
||||||
self.global_section().map(|gs| gs.entries().len()).unwrap_or(0)
|
self.global_section().map(|gs| gs.entries().len()).unwrap_or(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for Module {
|
impl Deserialize for Module {
|
||||||
type Error = super::Error;
|
type Error = super::Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let mut sections = Vec::new();
|
let mut sections = Vec::new();
|
||||||
|
|
||||||
let mut magic = [0u8; 4];
|
let mut magic = [0u8; 4];
|
||||||
reader.read(&mut magic)?;
|
reader.read(&mut magic)?;
|
||||||
if magic != WASM_MAGIC_NUMBER {
|
if magic != WASM_MAGIC_NUMBER {
|
||||||
return Err(Error::InvalidMagic);
|
return Err(Error::InvalidMagic);
|
||||||
}
|
}
|
||||||
|
|
||||||
let version: u32 = Uint32::deserialize(reader)?.into();
|
let version: u32 = Uint32::deserialize(reader)?.into();
|
||||||
|
|
||||||
if version != 1 {
|
if version != 1 {
|
||||||
return Err(Error::UnsupportedVersion(version));
|
return Err(Error::UnsupportedVersion(version));
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match Section::deserialize(reader) {
|
match Section::deserialize(reader) {
|
||||||
Err(Error::UnexpectedEof) => { break; },
|
Err(Error::UnexpectedEof) => { break; },
|
||||||
Err(e) => { return Err(e) },
|
Err(e) => { return Err(e) },
|
||||||
Ok(section) => { sections.push(section); }
|
Ok(section) => { sections.push(section); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Module {
|
Ok(Module {
|
||||||
magic: LittleEndian::read_u32(&magic),
|
magic: LittleEndian::read_u32(&magic),
|
||||||
version: version,
|
version: version,
|
||||||
sections: sections,
|
sections: sections,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Module {
|
impl Serialize for Module {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> {
|
||||||
Uint32::from(self.magic).serialize(w)?;
|
Uint32::from(self.magic).serialize(w)?;
|
||||||
Uint32::from(self.version).serialize(w)?;
|
Uint32::from(self.version).serialize(w)?;
|
||||||
for section in self.sections.into_iter() {
|
for section in self.sections.into_iter() {
|
||||||
section.serialize(w)?;
|
section.serialize(w)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
struct PeekSection<'a> {
|
struct PeekSection<'a> {
|
||||||
cursor: usize,
|
cursor: usize,
|
||||||
region: &'a [u8],
|
region: &'a [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> io::Read for PeekSection<'a> {
|
impl<'a> io::Read for PeekSection<'a> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
|
||||||
let available = ::std::cmp::min(buf.len(), self.region.len() - self.cursor);
|
let available = ::std::cmp::min(buf.len(), self.region.len() - self.cursor);
|
||||||
if available < buf.len() {
|
if available < buf.len() {
|
||||||
return Err(::std::io::Error::from(::std::io::ErrorKind::UnexpectedEof));
|
return Err(::std::io::Error::from(::std::io::ErrorKind::UnexpectedEof));
|
||||||
}
|
}
|
||||||
|
|
||||||
let range = self.cursor..self.cursor + buf.len();
|
let range = self.cursor..self.cursor + buf.len();
|
||||||
buf.copy_from_slice(&self.region[range]);
|
buf.copy_from_slice(&self.region[range]);
|
||||||
|
|
||||||
self.cursor += available;
|
self.cursor += available;
|
||||||
Ok(available)
|
Ok(available)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns size of the module in the provided stream
|
/// Returns size of the module in the provided stream
|
||||||
pub fn peek_size(source: &[u8]) -> usize {
|
pub fn peek_size(source: &[u8]) -> usize {
|
||||||
if source.len() < 9 {
|
if source.len() < 9 {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut cursor = 8;
|
let mut cursor = 8;
|
||||||
loop {
|
loop {
|
||||||
let (new_cursor, section_id, section_len) = {
|
let (new_cursor, section_id, section_len) = {
|
||||||
let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] };
|
let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] };
|
||||||
let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) {
|
let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) {
|
||||||
Ok(res) => res.into(),
|
Ok(res) => res.into(),
|
||||||
Err(_) => { break; },
|
Err(_) => { break; },
|
||||||
};
|
};
|
||||||
let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) {
|
let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) {
|
||||||
Ok(res) => res.into(),
|
Ok(res) => res.into(),
|
||||||
Err(_) => { break; },
|
Err(_) => { break; },
|
||||||
};
|
};
|
||||||
|
|
||||||
(peek_section.cursor, section_id, section_len)
|
(peek_section.cursor, section_id, section_len)
|
||||||
};
|
};
|
||||||
|
|
||||||
if section_id <= 11 && section_len > 0 {
|
if section_id <= 11 && section_len > 0 {
|
||||||
let next_cursor = cursor + new_cursor + section_len as usize;
|
let next_cursor = cursor + new_cursor + section_len as usize;
|
||||||
if next_cursor >= source.len() {
|
if next_cursor >= source.len() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cursor = next_cursor;
|
cursor = next_cursor;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor
|
cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod integration_tests {
|
mod integration_tests {
|
||||||
|
|
||||||
use super::super::{deserialize_file, serialize, deserialize_buffer, Section};
|
use super::super::{deserialize_file, serialize, deserialize_buffer, Section};
|
||||||
use super::Module;
|
use super::Module;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hello() {
|
fn hello() {
|
||||||
let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");
|
let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");
|
||||||
|
|
||||||
assert_eq!(module.version(), 1);
|
assert_eq!(module.version(), 1);
|
||||||
assert_eq!(module.sections().len(), 8);
|
assert_eq!(module.sections().len(), 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serde() {
|
fn serde() {
|
||||||
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||||
let buf = serialize(module).expect("serialization to succeed");
|
let buf = serialize(module).expect("serialization to succeed");
|
||||||
|
|
||||||
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
|
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
|
||||||
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||||
|
|
||||||
assert_eq!(module_old.sections().len(), module_new.sections().len());
|
assert_eq!(module_old.sections().len(), module_new.sections().len());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serde_type() {
|
fn serde_type() {
|
||||||
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||||
module.sections_mut().retain(|x| {
|
module.sections_mut().retain(|x| {
|
||||||
if let &Section::Type(_) = x { true } else { false }
|
if let &Section::Type(_) = x { true } else { false }
|
||||||
});
|
});
|
||||||
|
|
||||||
let buf = serialize(module).expect("serialization to succeed");
|
let buf = serialize(module).expect("serialization to succeed");
|
||||||
|
|
||||||
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
|
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
|
||||||
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
module_old.type_section().expect("type section exists").types().len(),
|
module_old.type_section().expect("type section exists").types().len(),
|
||||||
module_new.type_section().expect("type section exists").types().len(),
|
module_new.type_section().expect("type section exists").types().len(),
|
||||||
"There should be equal amount of types before and after serialization"
|
"There should be equal amount of types before and after serialization"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serde_import() {
|
fn serde_import() {
|
||||||
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||||
module.sections_mut().retain(|x| {
|
module.sections_mut().retain(|x| {
|
||||||
if let &Section::Import(_) = x { true } else { false }
|
if let &Section::Import(_) = x { true } else { false }
|
||||||
});
|
});
|
||||||
|
|
||||||
let buf = serialize(module).expect("serialization to succeed");
|
let buf = serialize(module).expect("serialization to succeed");
|
||||||
|
|
||||||
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
|
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
|
||||||
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
module_old.import_section().expect("import section exists").entries().len(),
|
module_old.import_section().expect("import section exists").entries().len(),
|
||||||
module_new.import_section().expect("import section exists").entries().len(),
|
module_new.import_section().expect("import section exists").entries().len(),
|
||||||
"There should be equal amount of import entries before and after serialization"
|
"There should be equal amount of import entries before and after serialization"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serde_code() {
|
fn serde_code() {
|
||||||
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||||
module.sections_mut().retain(|x| {
|
module.sections_mut().retain(|x| {
|
||||||
if let &Section::Code(_) = x { true } else { false }
|
if let &Section::Code(_) = x { true } else { false }
|
||||||
});
|
});
|
||||||
|
|
||||||
let buf = serialize(module).expect("serialization to succeed");
|
let buf = serialize(module).expect("serialization to succeed");
|
||||||
|
|
||||||
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
|
let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
|
||||||
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
module_old.code_section().expect("code section exists").bodies().len(),
|
module_old.code_section().expect("code section exists").bodies().len(),
|
||||||
module_new.code_section().expect("code section exists").bodies().len(),
|
module_new.code_section().expect("code section exists").bodies().len(),
|
||||||
"There should be equal amount of function bodies before and after serialization"
|
"There should be equal amount of function bodies before and after serialization"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn const_() {
|
fn const_() {
|
||||||
use super::super::Opcode::*;
|
use super::super::Opcode::*;
|
||||||
|
|
||||||
let module = deserialize_file("./res/cases/v1/const.wasm").expect("Should be deserialized");
|
let module = deserialize_file("./res/cases/v1/const.wasm").expect("Should be deserialized");
|
||||||
let func = &module.code_section().expect("Code section to exist").bodies()[0];
|
let func = &module.code_section().expect("Code section to exist").bodies()[0];
|
||||||
assert_eq!(func.code().elements().len(), 20);
|
assert_eq!(func.code().elements().len(), 20);
|
||||||
|
|
||||||
assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]);
|
assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]);
|
||||||
assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]);
|
assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]);
|
||||||
assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]);
|
assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]);
|
||||||
assert_eq!(I64Const(-8192), func.code().elements()[3]);
|
assert_eq!(I64Const(-8192), func.code().elements()[3]);
|
||||||
assert_eq!(I32Const(1024), func.code().elements()[4]);
|
assert_eq!(I32Const(1024), func.code().elements()[4]);
|
||||||
assert_eq!(I32Const(2048), func.code().elements()[5]);
|
assert_eq!(I32Const(2048), func.code().elements()[5]);
|
||||||
assert_eq!(I32Const(4096), func.code().elements()[6]);
|
assert_eq!(I32Const(4096), func.code().elements()[6]);
|
||||||
assert_eq!(I32Const(8192), func.code().elements()[7]);
|
assert_eq!(I32Const(8192), func.code().elements()[7]);
|
||||||
assert_eq!(I32Const(16384), func.code().elements()[8]);
|
assert_eq!(I32Const(16384), func.code().elements()[8]);
|
||||||
assert_eq!(I32Const(32767), func.code().elements()[9]);
|
assert_eq!(I32Const(32767), func.code().elements()[9]);
|
||||||
assert_eq!(I32Const(-1024), func.code().elements()[10]);
|
assert_eq!(I32Const(-1024), func.code().elements()[10]);
|
||||||
assert_eq!(I32Const(-2048), func.code().elements()[11]);
|
assert_eq!(I32Const(-2048), func.code().elements()[11]);
|
||||||
assert_eq!(I32Const(-4096), func.code().elements()[12]);
|
assert_eq!(I32Const(-4096), func.code().elements()[12]);
|
||||||
assert_eq!(I32Const(-8192), func.code().elements()[13]);
|
assert_eq!(I32Const(-8192), func.code().elements()[13]);
|
||||||
assert_eq!(I32Const(-16384), func.code().elements()[14]);
|
assert_eq!(I32Const(-16384), func.code().elements()[14]);
|
||||||
assert_eq!(I32Const(-32768), func.code().elements()[15]);
|
assert_eq!(I32Const(-32768), func.code().elements()[15]);
|
||||||
assert_eq!(I32Const(-2147483648), func.code().elements()[16]);
|
assert_eq!(I32Const(-2147483648), func.code().elements()[16]);
|
||||||
assert_eq!(I32Const(2147483647), func.code().elements()[17]);
|
assert_eq!(I32Const(2147483647), func.code().elements()[17]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn store() {
|
fn store() {
|
||||||
use super::super::Opcode::*;
|
use super::super::Opcode::*;
|
||||||
|
|
||||||
let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
|
let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
|
||||||
let func = &module.code_section().expect("Code section to exist").bodies()[0];
|
let func = &module.code_section().expect("Code section to exist").bodies()[0];
|
||||||
|
|
||||||
assert_eq!(func.code().elements().len(), 5);
|
assert_eq!(func.code().elements().len(), 5);
|
||||||
assert_eq!(I64Store(0, 32), func.code().elements()[2]);
|
assert_eq!(I64Store(0, 32), func.code().elements()[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn peek() {
|
fn peek() {
|
||||||
use super::peek_size;
|
use super::peek_size;
|
||||||
|
|
||||||
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
|
||||||
let mut buf = serialize(module).expect("serialization to succeed");
|
let mut buf = serialize(module).expect("serialization to succeed");
|
||||||
|
|
||||||
buf.extend_from_slice(&[1, 5, 12, 17]);
|
buf.extend_from_slice(&[1, 5, 12, 17]);
|
||||||
|
|
||||||
assert_eq!(peek_size(&buf), buf.len() - 4);
|
assert_eq!(peek_size(&buf), buf.len() - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn peek_2() {
|
fn peek_2() {
|
||||||
use super::peek_size;
|
use super::peek_size;
|
||||||
|
|
||||||
let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
|
let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
|
||||||
let mut buf = serialize(module).expect("serialization to succeed");
|
let mut buf = serialize(module).expect("serialization to succeed");
|
||||||
|
|
||||||
buf.extend_from_slice(&[0, 0, 0, 0, 0, 1, 5, 12, 17]);
|
buf.extend_from_slice(&[0, 0, 0, 0, 0, 1, 5, 12, 17]);
|
||||||
|
|
||||||
assert_eq!(peek_size(&buf), buf.len() - 9);
|
assert_eq!(peek_size(&buf), buf.len() - 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn module_default_round_trip() {
|
fn module_default_round_trip() {
|
||||||
let module1 = Module::default();
|
let module1 = Module::default();
|
||||||
let buf = serialize(module1).expect("Serialization should succeed");
|
let buf = serialize(module1).expect("Serialization should succeed");
|
||||||
|
|
||||||
let module2: Module = deserialize_buffer(&buf).expect("Deserialization should succeed");
|
let module2: Module = deserialize_buffer(&buf).expect("Deserialization should succeed");
|
||||||
assert_eq!(Module::default().magic, module2.magic);
|
assert_eq!(Module::default().magic, module2.magic);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn names() {
|
fn names() {
|
||||||
use super::super::name_section::NameSection;
|
use super::super::name_section::NameSection;
|
||||||
|
|
||||||
let module = deserialize_file("./res/cases/v1/with_names.wasm")
|
let module = deserialize_file("./res/cases/v1/with_names.wasm")
|
||||||
.expect("Should be deserialized")
|
.expect("Should be deserialized")
|
||||||
.parse_names()
|
.parse_names()
|
||||||
.expect("Names to be parsed");
|
.expect("Names to be parsed");
|
||||||
|
|
||||||
let mut found_section = false;
|
let mut found_section = false;
|
||||||
for section in module.sections() {
|
for section in module.sections() {
|
||||||
match *section {
|
match *section {
|
||||||
Section::Name(ref name_section) => {
|
Section::Name(ref name_section) => {
|
||||||
match *name_section {
|
match *name_section {
|
||||||
NameSection::Function(ref function_name_section) => {
|
NameSection::Function(ref function_name_section) => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
function_name_section.names().get(0).expect("Should be entry #0"),
|
function_name_section.names().get(0).expect("Should be entry #0"),
|
||||||
"elog"
|
"elog"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
function_name_section.names().get(11).expect("Should be entry #0"),
|
function_name_section.names().get(11).expect("Should be entry #0"),
|
||||||
"_ZN48_$LT$pwasm_token_contract..Endpoint$LT$T$GT$$GT$3new17hc3ace6dea0978cd9E"
|
"_ZN48_$LT$pwasm_token_contract..Endpoint$LT$T$GT$$GT$3new17hc3ace6dea0978cd9E"
|
||||||
);
|
);
|
||||||
|
|
||||||
found_section = true;
|
found_section = true;
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(found_section, "Name section should be present in dedicated example");
|
assert!(found_section, "Name section should be present in dedicated example");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,218 +10,218 @@ const NAME_TYPE_LOCAL: u8 = 2;
|
|||||||
/// Debug name information.
|
/// Debug name information.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum NameSection {
|
pub enum NameSection {
|
||||||
/// Module name section.
|
/// Module name section.
|
||||||
Module(ModuleNameSection),
|
Module(ModuleNameSection),
|
||||||
|
|
||||||
/// Function name section.
|
/// Function name section.
|
||||||
Function(FunctionNameSection),
|
Function(FunctionNameSection),
|
||||||
|
|
||||||
/// Local name section.
|
/// Local name section.
|
||||||
Local(LocalNameSection),
|
Local(LocalNameSection),
|
||||||
|
|
||||||
/// Name section is unparsed.
|
/// Name section is unparsed.
|
||||||
Unparsed {
|
Unparsed {
|
||||||
/// The numeric identifier for this name section type.
|
/// The numeric identifier for this name section type.
|
||||||
name_type: u8,
|
name_type: u8,
|
||||||
/// The contents of this name section, unparsed.
|
/// The contents of this name section, unparsed.
|
||||||
name_payload: Vec<u8>,
|
name_payload: Vec<u8>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NameSection {
|
impl NameSection {
|
||||||
/// Deserialize a name section.
|
/// Deserialize a name section.
|
||||||
pub fn deserialize<R: Read>(
|
pub fn deserialize<R: Read>(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
rdr: &mut R,
|
rdr: &mut R,
|
||||||
) -> Result<NameSection, Error> {
|
) -> Result<NameSection, Error> {
|
||||||
let name_type: u8 = VarUint7::deserialize(rdr)?.into();
|
let name_type: u8 = VarUint7::deserialize(rdr)?.into();
|
||||||
let name_payload_len: u32 = VarUint32::deserialize(rdr)?.into();
|
let name_payload_len: u32 = VarUint32::deserialize(rdr)?.into();
|
||||||
let name_section = match name_type {
|
let name_section = match name_type {
|
||||||
NAME_TYPE_MODULE => NameSection::Module(ModuleNameSection::deserialize(rdr)?),
|
NAME_TYPE_MODULE => NameSection::Module(ModuleNameSection::deserialize(rdr)?),
|
||||||
NAME_TYPE_FUNCTION => NameSection::Function(FunctionNameSection::deserialize(module, rdr)?),
|
NAME_TYPE_FUNCTION => NameSection::Function(FunctionNameSection::deserialize(module, rdr)?),
|
||||||
NAME_TYPE_LOCAL => NameSection::Local(LocalNameSection::deserialize(module, rdr)?),
|
NAME_TYPE_LOCAL => NameSection::Local(LocalNameSection::deserialize(module, rdr)?),
|
||||||
_ => {
|
_ => {
|
||||||
let mut name_payload = vec![0u8; name_payload_len as usize];
|
let mut name_payload = vec![0u8; name_payload_len as usize];
|
||||||
rdr.read_exact(&mut name_payload)?;
|
rdr.read_exact(&mut name_payload)?;
|
||||||
NameSection::Unparsed {
|
NameSection::Unparsed {
|
||||||
name_type,
|
name_type,
|
||||||
name_payload,
|
name_payload,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(name_section)
|
Ok(name_section)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for NameSection {
|
impl Serialize for NameSection {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||||
let (name_type, name_payload) = match self {
|
let (name_type, name_payload) = match self {
|
||||||
NameSection::Module(mod_name) => {
|
NameSection::Module(mod_name) => {
|
||||||
let mut buffer = vec![];
|
let mut buffer = vec![];
|
||||||
mod_name.serialize(&mut buffer)?;
|
mod_name.serialize(&mut buffer)?;
|
||||||
(NAME_TYPE_MODULE, buffer)
|
(NAME_TYPE_MODULE, buffer)
|
||||||
}
|
}
|
||||||
NameSection::Function(fn_names) => {
|
NameSection::Function(fn_names) => {
|
||||||
let mut buffer = vec![];
|
let mut buffer = vec![];
|
||||||
fn_names.serialize(&mut buffer)?;
|
fn_names.serialize(&mut buffer)?;
|
||||||
(NAME_TYPE_FUNCTION, buffer)
|
(NAME_TYPE_FUNCTION, buffer)
|
||||||
}
|
}
|
||||||
NameSection::Local(local_names) => {
|
NameSection::Local(local_names) => {
|
||||||
let mut buffer = vec![];
|
let mut buffer = vec![];
|
||||||
local_names.serialize(&mut buffer)?;
|
local_names.serialize(&mut buffer)?;
|
||||||
(NAME_TYPE_LOCAL, buffer)
|
(NAME_TYPE_LOCAL, buffer)
|
||||||
}
|
}
|
||||||
NameSection::Unparsed {
|
NameSection::Unparsed {
|
||||||
name_type,
|
name_type,
|
||||||
name_payload,
|
name_payload,
|
||||||
} => (name_type, name_payload),
|
} => (name_type, name_payload),
|
||||||
};
|
};
|
||||||
VarUint7::from(name_type).serialize(wtr)?;
|
VarUint7::from(name_type).serialize(wtr)?;
|
||||||
VarUint32::from(name_payload.len()).serialize(wtr)?;
|
VarUint32::from(name_payload.len()).serialize(wtr)?;
|
||||||
wtr.write_all(&name_payload)?;
|
wtr.write_all(&name_payload)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The name of this module.
|
/// The name of this module.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct ModuleNameSection {
|
pub struct ModuleNameSection {
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleNameSection {
|
impl ModuleNameSection {
|
||||||
/// Create a new module name section with the specified name.
|
/// Create a new module name section with the specified name.
|
||||||
pub fn new<S: Into<String>>(name: S) -> ModuleNameSection {
|
pub fn new<S: Into<String>>(name: S) -> ModuleNameSection {
|
||||||
ModuleNameSection { name: name.into() }
|
ModuleNameSection { name: name.into() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The name of this module.
|
/// The name of this module.
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The name of this module (mutable).
|
/// The name of this module (mutable).
|
||||||
pub fn name_mut(&mut self) -> &mut String {
|
pub fn name_mut(&mut self) -> &mut String {
|
||||||
&mut self.name
|
&mut self.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for ModuleNameSection {
|
impl Serialize for ModuleNameSection {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||||
self.name.serialize(wtr)
|
self.name.serialize(wtr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for ModuleNameSection {
|
impl Deserialize for ModuleNameSection {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: Read>(rdr: &mut R) -> Result<ModuleNameSection, Error> {
|
fn deserialize<R: Read>(rdr: &mut R) -> Result<ModuleNameSection, Error> {
|
||||||
let name = String::deserialize(rdr)?;
|
let name = String::deserialize(rdr)?;
|
||||||
Ok(ModuleNameSection { name })
|
Ok(ModuleNameSection { name })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The names of the functions in this module.
|
/// The names of the functions in this module.
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
pub struct FunctionNameSection {
|
pub struct FunctionNameSection {
|
||||||
names: NameMap,
|
names: NameMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionNameSection {
|
impl FunctionNameSection {
|
||||||
/// A map from function indices to names.
|
/// A map from function indices to names.
|
||||||
pub fn names(&self) -> &NameMap {
|
pub fn names(&self) -> &NameMap {
|
||||||
&self.names
|
&self.names
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A map from function indices to names (mutable).
|
/// A map from function indices to names (mutable).
|
||||||
pub fn names_mut(&mut self) -> &mut NameMap {
|
pub fn names_mut(&mut self) -> &mut NameMap {
|
||||||
&mut self.names
|
&mut self.names
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize names, making sure that all names correspond to functions.
|
/// Deserialize names, making sure that all names correspond to functions.
|
||||||
pub fn deserialize<R: Read>(
|
pub fn deserialize<R: Read>(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
rdr: &mut R,
|
rdr: &mut R,
|
||||||
) -> Result<FunctionNameSection, Error> {
|
) -> Result<FunctionNameSection, Error> {
|
||||||
let names = IndexMap::deserialize(module.functions_space(), rdr)?;
|
let names = IndexMap::deserialize(module.functions_space(), rdr)?;
|
||||||
Ok(FunctionNameSection { names })
|
Ok(FunctionNameSection { names })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for FunctionNameSection {
|
impl Serialize for FunctionNameSection {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||||
self.names.serialize(wtr)
|
self.names.serialize(wtr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The names of the local variables in this module's functions.
|
/// The names of the local variables in this module's functions.
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
pub struct LocalNameSection {
|
pub struct LocalNameSection {
|
||||||
local_names: IndexMap<NameMap>,
|
local_names: IndexMap<NameMap>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LocalNameSection {
|
impl LocalNameSection {
|
||||||
/// A map from function indices to a map from variables indices to names.
|
/// A map from function indices to a map from variables indices to names.
|
||||||
pub fn local_names(&self) -> &IndexMap<NameMap> {
|
pub fn local_names(&self) -> &IndexMap<NameMap> {
|
||||||
&self.local_names
|
&self.local_names
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A map from function indices to a map from variables indices to names
|
/// A map from function indices to a map from variables indices to names
|
||||||
/// (mutable).
|
/// (mutable).
|
||||||
pub fn local_names_mut(&mut self) -> &mut IndexMap<NameMap> {
|
pub fn local_names_mut(&mut self) -> &mut IndexMap<NameMap> {
|
||||||
&mut self.local_names
|
&mut self.local_names
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserialize names, making sure that all names correspond to local
|
/// Deserialize names, making sure that all names correspond to local
|
||||||
/// variables.
|
/// variables.
|
||||||
pub fn deserialize<R: Read>(
|
pub fn deserialize<R: Read>(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
rdr: &mut R,
|
rdr: &mut R,
|
||||||
) -> Result<LocalNameSection, Error> {
|
) -> Result<LocalNameSection, Error> {
|
||||||
let funcs = module.function_section().ok_or_else(|| {
|
let funcs = module.function_section().ok_or_else(|| {
|
||||||
Error::Other("cannot deserialize local names without a function section")
|
Error::Other("cannot deserialize local names without a function section")
|
||||||
})?;
|
})?;
|
||||||
let max_entry_space = funcs.entries().len();
|
let max_entry_space = funcs.entries().len();
|
||||||
|
|
||||||
let max_signature_args = module
|
let max_signature_args = module
|
||||||
.type_section()
|
.type_section()
|
||||||
.map(|ts|
|
.map(|ts|
|
||||||
ts.types()
|
ts.types()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| { let Type::Function(ref func) = *x; func.params().len() })
|
.map(|x| { let Type::Function(ref func) = *x; func.params().len() })
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(0))
|
.unwrap_or(0))
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
let max_locals = module
|
let max_locals = module
|
||||||
.code_section()
|
.code_section()
|
||||||
.map(|cs| cs.bodies().iter().map(|f| f.locals().len()).max().unwrap_or(0))
|
.map(|cs| cs.bodies().iter().map(|f| f.locals().len()).max().unwrap_or(0))
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
let max_space = max_signature_args + max_locals;
|
let max_space = max_signature_args + max_locals;
|
||||||
|
|
||||||
let deserialize_locals = |_: u32, rdr: &mut R| IndexMap::deserialize(max_space, rdr);
|
let deserialize_locals = |_: u32, rdr: &mut R| IndexMap::deserialize(max_space, rdr);
|
||||||
|
|
||||||
let local_names = IndexMap::deserialize_with(
|
let local_names = IndexMap::deserialize_with(
|
||||||
max_entry_space,
|
max_entry_space,
|
||||||
&deserialize_locals,
|
&deserialize_locals,
|
||||||
rdr,
|
rdr,
|
||||||
)?;
|
)?;
|
||||||
Ok(LocalNameSection { local_names })
|
Ok(LocalNameSection { local_names })
|
||||||
}}
|
}}
|
||||||
|
|
||||||
impl Serialize for LocalNameSection {
|
impl Serialize for LocalNameSection {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
fn serialize<W: Write>(self, wtr: &mut W) -> Result<(), Error> {
|
||||||
self.local_names.serialize(wtr)
|
self.local_names.serialize(wtr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A map from indices to names.
|
/// A map from indices to names.
|
||||||
@ -229,48 +229,48 @@ pub type NameMap = IndexMap<String>;
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// A helper funtion for the tests. Serialize a section, deserialize it,
|
// A helper funtion for the tests. Serialize a section, deserialize it,
|
||||||
// and make sure it matches the original.
|
// and make sure it matches the original.
|
||||||
fn serialize_test(original: NameSection) -> Vec<u8> {
|
fn serialize_test(original: NameSection) -> Vec<u8> {
|
||||||
let mut buffer = vec![];
|
let mut buffer = vec![];
|
||||||
original
|
original
|
||||||
.serialize(&mut buffer)
|
.serialize(&mut buffer)
|
||||||
.expect("serialize error");
|
.expect("serialize error");
|
||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_module_name() {
|
fn serialize_module_name() {
|
||||||
let original = NameSection::Module(ModuleNameSection::new("my_mod"));
|
let original = NameSection::Module(ModuleNameSection::new("my_mod"));
|
||||||
serialize_test(original.clone());
|
serialize_test(original.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_function_names() {
|
fn serialize_function_names() {
|
||||||
let mut sect = FunctionNameSection::default();
|
let mut sect = FunctionNameSection::default();
|
||||||
sect.names_mut().insert(0, "hello_world".to_string());
|
sect.names_mut().insert(0, "hello_world".to_string());
|
||||||
serialize_test(NameSection::Function(sect));
|
serialize_test(NameSection::Function(sect));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_local_names() {
|
fn serialize_local_names() {
|
||||||
let mut sect = LocalNameSection::default();
|
let mut sect = LocalNameSection::default();
|
||||||
let mut locals = NameMap::default();
|
let mut locals = NameMap::default();
|
||||||
locals.insert(0, "msg".to_string());
|
locals.insert(0, "msg".to_string());
|
||||||
sect.local_names_mut().insert(0, locals);
|
sect.local_names_mut().insert(0, locals);
|
||||||
serialize_test(NameSection::Local(sect));
|
serialize_test(NameSection::Local(sect));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_and_deserialize_unparsed() {
|
fn serialize_and_deserialize_unparsed() {
|
||||||
let original = NameSection::Unparsed {
|
let original = NameSection::Unparsed {
|
||||||
// A made-up name section type which is unlikely to be allocated
|
// A made-up name section type which is unlikely to be allocated
|
||||||
// soon, in order to allow us to test `Unparsed`.
|
// soon, in order to allow us to test `Unparsed`.
|
||||||
name_type: 120,
|
name_type: 120,
|
||||||
name_payload: vec![0u8, 1, 2],
|
name_payload: vec![0u8, 1, 2],
|
||||||
};
|
};
|
||||||
serialize_test(original.clone());
|
serialize_test(original.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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.
|
/// Entry in the element section.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ElementSegment {
|
pub struct ElementSegment {
|
||||||
index: u32,
|
index: u32,
|
||||||
offset: InitExpr,
|
offset: InitExpr,
|
||||||
members: Vec<u32>,
|
members: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ElementSegment {
|
impl ElementSegment {
|
||||||
/// New element segment.
|
/// New element segment.
|
||||||
pub fn new(index: u32, offset: InitExpr, members: Vec<u32>) -> Self {
|
pub fn new(index: u32, offset: InitExpr, members: Vec<u32>) -> Self {
|
||||||
ElementSegment { index: index, offset: offset, members: members }
|
ElementSegment { index: index, offset: offset, members: members }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sequence of function indices.
|
/// Sequence of function indices.
|
||||||
pub fn members(&self) -> &[u32] { &self.members }
|
pub fn members(&self) -> &[u32] { &self.members }
|
||||||
|
|
||||||
/// Sequence of function indices (mutable)
|
/// Sequence of function indices (mutable)
|
||||||
pub fn members_mut(&mut self) -> &mut Vec<u32> { &mut self.members }
|
pub fn members_mut(&mut self) -> &mut Vec<u32> { &mut self.members }
|
||||||
|
|
||||||
/// Table index (currently valid only value of `0`)
|
/// Table index (currently valid only value of `0`)
|
||||||
pub fn index(&self) -> u32 { self.index }
|
pub fn index(&self) -> u32 { self.index }
|
||||||
|
|
||||||
/// An i32 initializer expression that computes the offset at which to place the elements.
|
/// An i32 initializer expression that computes the offset at which to place the elements.
|
||||||
pub fn offset(&self) -> &InitExpr { &self.offset }
|
pub fn offset(&self) -> &InitExpr { &self.offset }
|
||||||
|
|
||||||
/// An i32 initializer expression that computes the offset at which to place the elements (mutable)
|
/// An i32 initializer expression that computes the offset at which to place the elements (mutable)
|
||||||
pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset }
|
pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for ElementSegment {
|
impl Deserialize for ElementSegment {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let index = VarUint32::deserialize(reader)?;
|
let index = VarUint32::deserialize(reader)?;
|
||||||
let offset = InitExpr::deserialize(reader)?;
|
let offset = InitExpr::deserialize(reader)?;
|
||||||
let funcs: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
|
let funcs: Vec<u32> = CountedList::<VarUint32>::deserialize(reader)?
|
||||||
.into_inner()
|
.into_inner()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(ElementSegment {
|
Ok(ElementSegment {
|
||||||
index: index.into(),
|
index: index.into(),
|
||||||
offset: offset,
|
offset: offset,
|
||||||
members: funcs,
|
members: funcs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for ElementSegment {
|
impl Serialize for ElementSegment {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
VarUint32::from(self.index).serialize(writer)?;
|
VarUint32::from(self.index).serialize(writer)?;
|
||||||
self.offset.serialize(writer)?;
|
self.offset.serialize(writer)?;
|
||||||
let data = self.members;
|
let data = self.members;
|
||||||
let counted_list = CountedListWriter::<VarUint32, _>(
|
let counted_list = CountedListWriter::<VarUint32, _>(
|
||||||
data.len(),
|
data.len(),
|
||||||
data.into_iter().map(Into::into),
|
data.into_iter().map(Into::into),
|
||||||
);
|
);
|
||||||
counted_list.serialize(writer)?;
|
counted_list.serialize(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data segment definition.
|
/// Data segment definition.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DataSegment {
|
pub struct DataSegment {
|
||||||
index: u32,
|
index: u32,
|
||||||
offset: InitExpr,
|
offset: InitExpr,
|
||||||
value: Vec<u8>,
|
value: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataSegment {
|
impl DataSegment {
|
||||||
/// New data segments.
|
/// New data segments.
|
||||||
pub fn new(index: u32, offset: InitExpr, value: Vec<u8>) -> Self {
|
pub fn new(index: u32, offset: InitExpr, value: Vec<u8>) -> Self {
|
||||||
DataSegment {
|
DataSegment {
|
||||||
index: index,
|
index: index,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
value: value,
|
value: value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Linear memory index (currently the only valid value is `0`).
|
/// Linear memory index (currently the only valid value is `0`).
|
||||||
pub fn index(&self) -> u32 { self.index }
|
pub fn index(&self) -> u32 { self.index }
|
||||||
|
|
||||||
/// An i32 initializer expression that computes the offset at which to place the data.
|
/// An i32 initializer expression that computes the offset at which to place the data.
|
||||||
pub fn offset(&self) -> &InitExpr { &self.offset }
|
pub fn offset(&self) -> &InitExpr { &self.offset }
|
||||||
|
|
||||||
/// An i32 initializer expression that computes the offset at which to place the data (mutable)
|
/// An i32 initializer expression that computes the offset at which to place the data (mutable)
|
||||||
pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset }
|
pub fn offset_mut(&mut self) -> &mut InitExpr { &mut self.offset }
|
||||||
|
|
||||||
/// Initial value of the data segment.
|
/// Initial value of the data segment.
|
||||||
pub fn value(&self) -> &[u8] { &self.value }
|
pub fn value(&self) -> &[u8] { &self.value }
|
||||||
|
|
||||||
/// Initial value of the data segment (mutable).
|
/// Initial value of the data segment (mutable).
|
||||||
pub fn value_mut(&mut self) -> &mut Vec<u8> { &mut self.value }
|
pub fn value_mut(&mut self) -> &mut Vec<u8> { &mut self.value }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for DataSegment {
|
impl Deserialize for DataSegment {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let index = VarUint32::deserialize(reader)?;
|
let index = VarUint32::deserialize(reader)?;
|
||||||
let offset = InitExpr::deserialize(reader)?;
|
let offset = InitExpr::deserialize(reader)?;
|
||||||
let value_len = VarUint32::deserialize(reader)?;
|
let value_len = VarUint32::deserialize(reader)?;
|
||||||
|
|
||||||
let mut value_buf = vec![0u8; value_len.into()];
|
let mut value_buf = vec![0u8; value_len.into()];
|
||||||
reader.read_exact(&mut value_buf[..])?;
|
reader.read_exact(&mut value_buf[..])?;
|
||||||
|
|
||||||
Ok(DataSegment {
|
Ok(DataSegment {
|
||||||
index: index.into(),
|
index: index.into(),
|
||||||
offset: offset,
|
offset: offset,
|
||||||
value: value_buf,
|
value: value_buf,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for DataSegment {
|
impl Serialize for DataSegment {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
VarUint32::from(self.index).serialize(writer)?;
|
VarUint32::from(self.index).serialize(writer)?;
|
||||||
self.offset.serialize(writer)?;
|
self.offset.serialize(writer)?;
|
||||||
|
|
||||||
let value = self.value;
|
let value = self.value;
|
||||||
VarUint32::from(value.len()).serialize(writer)?;
|
VarUint32::from(value.len()).serialize(writer)?;
|
||||||
writer.write_all(&value[..])?;
|
writer.write_all(&value[..])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,245 +1,245 @@
|
|||||||
use std::{io, fmt};
|
use std::{io, fmt};
|
||||||
use super::{
|
use super::{
|
||||||
Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint1, CountedList,
|
Deserialize, Serialize, Error, VarUint7, VarInt7, VarUint1, CountedList,
|
||||||
CountedListWriter
|
CountedListWriter
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Type definition in types section. Currently can be only of the function type.
|
/// Type definition in types section. Currently can be only of the function type.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
/// Function type.
|
/// Function type.
|
||||||
Function(FunctionType),
|
Function(FunctionType),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for Type {
|
impl Deserialize for Type {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
Ok(Type::Function(FunctionType::deserialize(reader)?))
|
Ok(Type::Function(FunctionType::deserialize(reader)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Type {
|
impl Serialize for Type {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
match self {
|
match self {
|
||||||
Type::Function(fn_type) => fn_type.serialize(writer)
|
Type::Function(fn_type) => fn_type.serialize(writer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Value type.
|
/// Value type.
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
pub enum ValueType {
|
pub enum ValueType {
|
||||||
/// 32-bit signed integer
|
/// 32-bit signed integer
|
||||||
I32,
|
I32,
|
||||||
/// 64-bit signed integer
|
/// 64-bit signed integer
|
||||||
I64,
|
I64,
|
||||||
/// 32-bit float
|
/// 32-bit float
|
||||||
F32,
|
F32,
|
||||||
/// 64-bit float
|
/// 64-bit float
|
||||||
F64,
|
F64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for ValueType {
|
impl Deserialize for ValueType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let val = VarInt7::deserialize(reader)?;
|
let val = VarInt7::deserialize(reader)?;
|
||||||
|
|
||||||
match val.into() {
|
match val.into() {
|
||||||
-0x01 => Ok(ValueType::I32),
|
-0x01 => Ok(ValueType::I32),
|
||||||
-0x02 => Ok(ValueType::I64),
|
-0x02 => Ok(ValueType::I64),
|
||||||
-0x03 => Ok(ValueType::F32),
|
-0x03 => Ok(ValueType::F32),
|
||||||
-0x04 => Ok(ValueType::F64),
|
-0x04 => Ok(ValueType::F64),
|
||||||
_ => Err(Error::UnknownValueType(val.into())),
|
_ => Err(Error::UnknownValueType(val.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for ValueType {
|
impl Serialize for ValueType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
let val: VarInt7 = match self {
|
let val: VarInt7 = match self {
|
||||||
ValueType::I32 => -0x01,
|
ValueType::I32 => -0x01,
|
||||||
ValueType::I64 => -0x02,
|
ValueType::I64 => -0x02,
|
||||||
ValueType::F32 => -0x03,
|
ValueType::F32 => -0x03,
|
||||||
ValueType::F64 => -0x04,
|
ValueType::F64 => -0x04,
|
||||||
}.into();
|
}.into();
|
||||||
val.serialize(writer)?;
|
val.serialize(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ValueType {
|
impl fmt::Display for ValueType {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ValueType::I32 => write!(f, "i32"),
|
ValueType::I32 => write!(f, "i32"),
|
||||||
ValueType::I64 => write!(f, "i64"),
|
ValueType::I64 => write!(f, "i64"),
|
||||||
ValueType::F32 => write!(f, "f32"),
|
ValueType::F32 => write!(f, "f32"),
|
||||||
ValueType::F64 => write!(f, "f64"),
|
ValueType::F64 => write!(f, "f64"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Block type which is basically `ValueType` + NoResult (to define blocks that have no return type)
|
/// Block type which is basically `ValueType` + NoResult (to define blocks that have no return type)
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
pub enum BlockType {
|
pub enum BlockType {
|
||||||
/// Value-type specified block type
|
/// Value-type specified block type
|
||||||
Value(ValueType),
|
Value(ValueType),
|
||||||
/// No specified block type
|
/// No specified block type
|
||||||
NoResult,
|
NoResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for BlockType {
|
impl Deserialize for BlockType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let val = VarInt7::deserialize(reader)?;
|
let val = VarInt7::deserialize(reader)?;
|
||||||
|
|
||||||
match val.into() {
|
match val.into() {
|
||||||
-0x01 => Ok(BlockType::Value(ValueType::I32)),
|
-0x01 => Ok(BlockType::Value(ValueType::I32)),
|
||||||
-0x02 => Ok(BlockType::Value(ValueType::I64)),
|
-0x02 => Ok(BlockType::Value(ValueType::I64)),
|
||||||
-0x03 => Ok(BlockType::Value(ValueType::F32)),
|
-0x03 => Ok(BlockType::Value(ValueType::F32)),
|
||||||
-0x04 => Ok(BlockType::Value(ValueType::F64)),
|
-0x04 => Ok(BlockType::Value(ValueType::F64)),
|
||||||
-0x40 => Ok(BlockType::NoResult),
|
-0x40 => Ok(BlockType::NoResult),
|
||||||
_ => Err(Error::UnknownValueType(val.into())),
|
_ => Err(Error::UnknownValueType(val.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for BlockType {
|
impl Serialize for BlockType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
let val: VarInt7 = match self {
|
let val: VarInt7 = match self {
|
||||||
BlockType::NoResult => -0x40i8,
|
BlockType::NoResult => -0x40i8,
|
||||||
BlockType::Value(ValueType::I32) => -0x01,
|
BlockType::Value(ValueType::I32) => -0x01,
|
||||||
BlockType::Value(ValueType::I64) => -0x02,
|
BlockType::Value(ValueType::I64) => -0x02,
|
||||||
BlockType::Value(ValueType::F32) => -0x03,
|
BlockType::Value(ValueType::F32) => -0x03,
|
||||||
BlockType::Value(ValueType::F64) => -0x04,
|
BlockType::Value(ValueType::F64) => -0x04,
|
||||||
}.into();
|
}.into();
|
||||||
val.serialize(writer)?;
|
val.serialize(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function signature type.
|
/// Function signature type.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct FunctionType {
|
pub struct FunctionType {
|
||||||
form: u8,
|
form: u8,
|
||||||
params: Vec<ValueType>,
|
params: Vec<ValueType>,
|
||||||
return_type: Option<ValueType>,
|
return_type: Option<ValueType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FunctionType {
|
impl Default for FunctionType {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
FunctionType {
|
FunctionType {
|
||||||
form: 0x60,
|
form: 0x60,
|
||||||
params: Vec::new(),
|
params: Vec::new(),
|
||||||
return_type: None,
|
return_type: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionType {
|
impl FunctionType {
|
||||||
/// New function type given the signature in-params(`params`) and return type (`return_type`)
|
/// New function type given the signature in-params(`params`) and return type (`return_type`)
|
||||||
pub fn new(params: Vec<ValueType>, return_type: Option<ValueType>) -> Self {
|
pub fn new(params: Vec<ValueType>, return_type: Option<ValueType>) -> Self {
|
||||||
FunctionType {
|
FunctionType {
|
||||||
params: params,
|
params: params,
|
||||||
return_type: return_type,
|
return_type: return_type,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Function form (currently only valid value is `0x60`)
|
/// Function form (currently only valid value is `0x60`)
|
||||||
pub fn form(&self) -> u8 { self.form }
|
pub fn form(&self) -> u8 { self.form }
|
||||||
/// Parameters in the function signature.
|
/// Parameters in the function signature.
|
||||||
pub fn params(&self) -> &[ValueType] { &self.params }
|
pub fn params(&self) -> &[ValueType] { &self.params }
|
||||||
/// Mutable parameters in the function signature.
|
/// Mutable parameters in the function signature.
|
||||||
pub fn params_mut(&mut self) -> &mut Vec<ValueType> { &mut self.params }
|
pub fn params_mut(&mut self) -> &mut Vec<ValueType> { &mut self.params }
|
||||||
/// Return type in the function signature, if any.
|
/// Return type in the function signature, if any.
|
||||||
pub fn return_type(&self) -> Option<ValueType> { self.return_type }
|
pub fn return_type(&self) -> Option<ValueType> { self.return_type }
|
||||||
/// Mutable type in the function signature, if any.
|
/// Mutable type in the function signature, if any.
|
||||||
pub fn return_type_mut(&mut self) -> &mut Option<ValueType> { &mut self.return_type }
|
pub fn return_type_mut(&mut self) -> &mut Option<ValueType> { &mut self.return_type }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for FunctionType {
|
impl Deserialize for FunctionType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let form: u8 = VarUint7::deserialize(reader)?.into();
|
let form: u8 = VarUint7::deserialize(reader)?.into();
|
||||||
|
|
||||||
let params: Vec<ValueType> = CountedList::deserialize(reader)?.into_inner();
|
let params: Vec<ValueType> = CountedList::deserialize(reader)?.into_inner();
|
||||||
|
|
||||||
let has_return_type = VarUint1::deserialize(reader)?;
|
let has_return_type = VarUint1::deserialize(reader)?;
|
||||||
let return_type = if has_return_type.into() {
|
let return_type = if has_return_type.into() {
|
||||||
Some(ValueType::deserialize(reader)?)
|
Some(ValueType::deserialize(reader)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(FunctionType {
|
Ok(FunctionType {
|
||||||
form: form,
|
form: form,
|
||||||
params: params,
|
params: params,
|
||||||
return_type: return_type,
|
return_type: return_type,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for FunctionType {
|
impl Serialize for FunctionType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
VarUint7::from(self.form).serialize(writer)?;
|
VarUint7::from(self.form).serialize(writer)?;
|
||||||
|
|
||||||
let data = self.params;
|
let data = self.params;
|
||||||
let counted_list = CountedListWriter::<ValueType, _>(
|
let counted_list = CountedListWriter::<ValueType, _>(
|
||||||
data.len(),
|
data.len(),
|
||||||
data.into_iter().map(Into::into),
|
data.into_iter().map(Into::into),
|
||||||
);
|
);
|
||||||
counted_list.serialize(writer)?;
|
counted_list.serialize(writer)?;
|
||||||
|
|
||||||
if let Some(return_type) = self.return_type {
|
if let Some(return_type) = self.return_type {
|
||||||
VarUint1::from(true).serialize(writer)?;
|
VarUint1::from(true).serialize(writer)?;
|
||||||
return_type.serialize(writer)?;
|
return_type.serialize(writer)?;
|
||||||
} else {
|
} else {
|
||||||
VarUint1::from(false).serialize(writer)?;
|
VarUint1::from(false).serialize(writer)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Table element type.
|
/// Table element type.
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
pub enum TableElementType {
|
pub enum TableElementType {
|
||||||
/// A reference to a function with any signature.
|
/// A reference to a function with any signature.
|
||||||
AnyFunc,
|
AnyFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for TableElementType {
|
impl Deserialize for TableElementType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
|
||||||
let val = VarInt7::deserialize(reader)?;
|
let val = VarInt7::deserialize(reader)?;
|
||||||
|
|
||||||
match val.into() {
|
match val.into() {
|
||||||
-0x10 => Ok(TableElementType::AnyFunc),
|
-0x10 => Ok(TableElementType::AnyFunc),
|
||||||
_ => Err(Error::UnknownTableElementType(val.into())),
|
_ => Err(Error::UnknownTableElementType(val.into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for TableElementType {
|
impl Serialize for TableElementType {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
fn serialize<W: io::Write>(self, writer: &mut W) -> Result<(), Self::Error> {
|
||||||
let val: VarInt7 = match self {
|
let val: VarInt7 = match self {
|
||||||
TableElementType::AnyFunc => 0x70,
|
TableElementType::AnyFunc => 0x70,
|
||||||
}.into();
|
}.into();
|
||||||
val.serialize(writer)?;
|
val.serialize(writer)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
src/lib.rs
20
src/lib.rs
@ -14,18 +14,18 @@ mod validation;
|
|||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
pub use elements::{
|
pub use elements::{
|
||||||
Error as SerializationError,
|
Error as SerializationError,
|
||||||
deserialize_buffer,
|
deserialize_buffer,
|
||||||
deserialize_file,
|
deserialize_file,
|
||||||
serialize,
|
serialize,
|
||||||
serialize_to_file,
|
serialize_to_file,
|
||||||
peek_size,
|
peek_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub use interpreter::{
|
pub use interpreter::{
|
||||||
ProgramInstance,
|
ProgramInstance,
|
||||||
ModuleInstance,
|
ModuleInstance,
|
||||||
ModuleInstanceInterface,
|
ModuleInstanceInterface,
|
||||||
RuntimeValue,
|
RuntimeValue,
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user