parity-wasm/src/builder/module.rs

228 lines
6.9 KiB
Rust
Raw Normal View History

2017-04-06 11:34:31 +03:00
use super::invoke::{Invoke, Identity};
2017-04-07 14:04:27 +03:00
use super::code::{self, SignaturesBuilder};
2017-04-06 11:34:31 +03:00
use elements;
/// Module builder
pub struct ModuleBuilder<F=Identity> {
callback: F,
2017-04-06 16:00:12 +03:00
module: ModuleScaffold,
}
2017-04-07 20:00:30 +03:00
/// Location of the internal module function
pub struct CodeLocation {
/// Location (index in 'functions' section) of the signature
pub signature: u32,
/// Location (index in the 'code' section) of the body
pub body: u32,
}
2017-04-06 16:00:12 +03:00
#[derive(Default)]
struct ModuleScaffold {
pub functions: elements::FunctionsSection,
pub types: elements::TypeSection,
2017-04-07 15:29:02 +03:00
pub import: elements::ImportSection,
2017-04-07 20:00:30 +03:00
pub code: elements::CodeSection,
2017-04-06 16:00:12 +03:00
pub other: Vec<elements::Section>,
}
impl From<elements::Module> for ModuleScaffold {
fn from(module: elements::Module) -> Self {
let mut funcs: Option<elements::FunctionsSection> = None;
let mut types: Option<elements::TypeSection> = None;
2017-04-07 15:29:02 +03:00
let mut import: Option<elements::ImportSection> = None;
2017-04-07 20:00:30 +03:00
let mut code: Option<elements::CodeSection> = None;
2017-04-06 16:00:12 +03:00
let mut sections = module.into_sections();
while let Some(section) = sections.pop() {
match section {
elements::Section::Type(sect) => { types = Some(sect); }
elements::Section::Function(sect) => { funcs = Some(sect); }
2017-04-07 15:29:02 +03:00
elements::Section::Import(sect) => { import = Some(sect); }
2017-04-07 20:00:30 +03:00
elements::Section::Code(sect) => { code = Some(sect); }
2017-04-06 16:00:12 +03:00
_ => {}
}
}
ModuleScaffold {
functions: funcs.unwrap_or_default(),
types: types.unwrap_or_default(),
2017-04-07 15:29:02 +03:00
import: import.unwrap_or_default(),
2017-04-07 20:00:30 +03:00
code: code.unwrap_or_default(),
2017-04-06 16:00:12 +03:00
other: sections,
}
}
}
impl From<ModuleScaffold> for elements::Module {
fn from(module: ModuleScaffold) -> Self {
let mut sections = Vec::new();
let types = module.types;
if types.types().len() > 0 {
sections.push(elements::Section::Type(types));
}
let functions = module.functions;
if functions.entries().len() > 0 {
sections.push(elements::Section::Function(functions));
}
2017-04-07 15:29:02 +03:00
let import = module.import;
if import.entries().len() > 0 {
sections.push(elements::Section::Import(import));
}
2017-04-06 16:00:12 +03:00
sections.extend(module.other);
elements::Module::new(sections)
}
2017-04-06 11:34:31 +03:00
}
impl ModuleBuilder {
/// New empty module builder
pub fn new() -> Self {
ModuleBuilder::with_callback(Identity)
}
}
impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
/// New module builder with bound callback
pub fn with_callback(callback: F) -> Self {
ModuleBuilder {
callback: callback,
2017-04-06 16:00:12 +03:00
module: Default::default(),
2017-04-06 11:34:31 +03:00
}
}
/// Fill module with sections from iterator
pub fn with_sections<I>(mut self, sections: I) -> Self
where I: IntoIterator<Item=elements::Section>
{
2017-04-06 16:00:12 +03:00
self.module.other.extend(sections);
2017-04-06 11:34:31 +03:00
self
}
2017-04-06 16:00:12 +03:00
/// Add additional section
2017-04-06 11:34:31 +03:00
pub fn with_section(mut self, section: elements::Section) -> Self {
2017-04-06 16:00:12 +03:00
self.module.other.push(section);
2017-04-06 11:34:31 +03:00
self
}
2017-04-06 16:00:12 +03:00
/// Binds to the type section, creates additional types when required
pub fn with_signatures(mut self, bindings: code::SignatureBindings) -> Self {
2017-04-07 14:04:27 +03:00
self.push_signatures(bindings);
self
}
2017-04-06 16:00:12 +03:00
2017-04-07 20:00:30 +03:00
/// Push stand-alone function definition, creating sections, signature and code blocks
/// in corresponding sections.
/// `FunctionDefinition` can be build using `builder::function` builder
pub fn push_function(&mut self, func: code::FunctionDefinition) -> CodeLocation {
let signature = func.signature;
let body = func.code;
let module = &mut self.module;
let type_ref = match signature {
code::Signature::Inline(func_type) => {
module.types.types_mut().push(elements::Type::Function(func_type));
module.types.types().len() as u32 - 1
}
code::Signature::TypeReference(type_ref) => {
type_ref
}
};
module.functions.entries_mut().push(elements::Func::new(type_ref));
let signature_index = module.functions.entries_mut().len() as u32 - 1;
module.code.bodies_mut().push(body);
let body_index = module.code.bodies_mut().len() as u32 - 1;
CodeLocation {
signature: signature_index,
body: body_index,
}
}
2017-04-07 14:04:27 +03:00
/// Push signatures in the module, returning corresponding indices of pushed signatures
pub fn push_signatures(&mut self, signatures: code::SignatureBindings) -> Vec<u32> {
let module = &mut self.module;
let mut result = Vec::new();
// todo: maybe reuse existing types with the equal signatures
let raw_functions: Vec<u32> = signatures.into_iter().map(|binding|
match binding {
code::Signature::Inline(func_type) => {
module.types.types_mut().push(elements::Type::Function(func_type));
module.types.types().len() as u32 - 1
}
code::Signature::TypeReference(type_ref) => {
type_ref
}
2017-04-06 16:00:12 +03:00
}
2017-04-07 14:04:27 +03:00
).collect();
for function in raw_functions {
module.functions.entries_mut().push(elements::Func::new(function));
result.push(module.functions.entries_mut().len() as u32 - 1);
2017-04-06 16:00:12 +03:00
}
2017-04-07 14:04:27 +03:00
result
2017-04-06 16:00:12 +03:00
}
/// Define functions section
2017-04-07 14:04:27 +03:00
pub fn functions(self) -> SignaturesBuilder<Self> {
SignaturesBuilder::with_callback(self)
2017-04-06 11:34:31 +03:00
}
/// Build module (final step)
pub fn build(self) -> F::Result {
2017-04-06 16:00:12 +03:00
self.callback.invoke(self.module.into())
2017-04-06 11:34:31 +03:00
}
}
impl<F> Invoke<elements::FunctionsSection> for ModuleBuilder<F>
where F: Invoke<elements::Module>
{
type Result = Self;
fn invoke(self, section: elements::FunctionsSection) -> Self {
self.with_section(elements::Section::Function(section))
}
}
2017-04-06 16:00:12 +03:00
impl<F> Invoke<code::SignatureBindings> for ModuleBuilder<F>
where F: Invoke<elements::Module>
{
type Result = Self;
fn invoke(self, bindings: code::SignatureBindings) -> Self {
self.with_signatures(bindings)
}
}
2017-04-06 11:34:31 +03:00
/// Start new module builder
pub fn module() -> ModuleBuilder {
ModuleBuilder::new()
}
#[cfg(test)]
mod tests {
use super::module;
#[test]
fn smoky() {
let module = module().build();
assert_eq!(module.sections().len(), 0);
}
2017-04-06 16:00:12 +03:00
#[test]
fn functions() {
let module = module()
.functions()
2017-04-06 18:23:02 +03:00
.signature().with_param(::elements::ValueType::I32).build()
2017-04-06 16:00:12 +03:00
.bind()
.build();
assert_eq!(module.type_section().expect("type section to exist").types().len(), 1);
assert_eq!(module.functions_section().expect("function section to exist").entries().len(), 1);
}
2017-04-06 11:34:31 +03:00
}