diff --git a/examples/build.rs b/examples/build.rs new file mode 100644 index 0000000..d836a61 --- /dev/null +++ b/examples/build.rs @@ -0,0 +1,22 @@ +extern crate parity_wasm; + +use std::env; + +use parity_wasm::builder; +use parity_wasm::elements; + +fn main() { + let args = env::args().collect::>(); + if args.len() != 2 { + println!("Usage: {} output_file.wasm", args[0]); + return; + } + + let module = builder::module() + .functions() + .signature().param(elements::ValueType::I32).build() + .bind() + .build(); + + parity_wasm::serialize_to_file(&args[1], module).unwrap(); +} \ No newline at end of file diff --git a/src/builder/code.rs b/src/builder/code.rs index a2dd102..053869a 100644 --- a/src/builder/code.rs +++ b/src/builder/code.rs @@ -8,49 +8,25 @@ pub enum Signature { pub struct SignatureBuilder { callback: F, - signature: Signature, + signature: elements::FunctionType, } -impl SignatureBuilder where F: Invoke { +impl SignatureBuilder where F: Invoke { pub fn with_callback(callback: F) -> Self { SignatureBuilder { callback: callback, - signature: Signature::TypeReference(0) + signature: elements::FunctionType::default(), } } - pub fn type_ref(mut self, val: u32) -> Self { - self.signature = Signature::TypeReference(val); - self - } - pub fn param(mut self, value_type: elements::ValueType) -> Self { - { - let signature = &mut self.signature; - if let Signature::TypeReference(_) = *signature { - *signature = Signature::Inline(elements::FunctionType::default()) - } - - if let Signature::Inline(ref mut func_type) = *signature { - func_type.params_mut().push(value_type); - } - } + self.signature.params_mut().push(value_type); self } pub fn return_type(mut self, value_type: elements::ValueType) -> Self { - { - let signature = &mut self.signature; - if let Signature::TypeReference(_) = *signature { - *signature = Signature::Inline(elements::FunctionType::default()) - } - - if let Signature::Inline(ref mut func_type) = *signature { - *func_type.return_type_mut() = Some(value_type); - } - } - + *self.signature.return_type_mut() = Some(value_type); self } @@ -59,6 +35,27 @@ impl SignatureBuilder where F: Invoke { } } +pub struct TypeRefBuilder { + callback: F, + type_ref: u32, +} + +impl TypeRefBuilder where F: Invoke { + pub fn with_callback(callback: F) -> Self { + TypeRefBuilder { + callback: callback, + type_ref: 0 + } + } + + pub fn val(mut self, val: u32) -> Self { + self.type_ref = val; + self + } + + pub fn build(self) -> F::Result { self.callback.invoke(self.type_ref) } +} + pub struct FunctionsBuilder { callback: F, section: Vec, @@ -84,16 +81,30 @@ impl FunctionsBuilder { self } + pub fn type_ref(self) -> TypeRefBuilder { + TypeRefBuilder::with_callback(self) + } +} + +impl FunctionsBuilder where F: Invoke { pub fn signature(self) -> SignatureBuilder { SignatureBuilder::with_callback(self) } } -impl Invoke for FunctionsBuilder { +impl Invoke for FunctionsBuilder { type Result = Self; - fn invoke(self, signature: Signature) -> Self { - self.with_signature(signature) + fn invoke(self, signature: elements::FunctionType) -> Self { + self.with_signature(Signature::Inline(signature)) + } +} + +impl Invoke for FunctionsBuilder { + type Result = Self; + + fn invoke(self, type_ref: u32) -> Self { + self.with_signature(Signature::TypeReference(type_ref)) } } @@ -119,21 +130,30 @@ impl FunctionsBuilder where F: Invoke { } } +/// New function builder. +pub fn function() -> FunctionsBuilder { + FunctionsBuilder::new() +} + #[cfg(test)] mod tests { - use super::FunctionsBuilder; + use super::function; #[test] fn example() { - let result = FunctionsBuilder::new() - .signature().type_ref(1).build() + let result = function() + .type_ref().val(1).build() .build(); assert_eq!(result.entries().len(), 1); - let result = FunctionsBuilder::new() - .signature().type_ref(1).build() + let result = function() + .signature() + .param(::elements::ValueType::I32) + .param(::elements::ValueType::I32) + .return_type(::elements::ValueType::I64) + .build() .bind(); assert_eq!(result.len(), 1); diff --git a/src/builder/mod.rs b/src/builder/mod.rs index f41fd90..7254828 100644 --- a/src/builder/mod.rs +++ b/src/builder/mod.rs @@ -4,4 +4,5 @@ mod invoke; mod module; mod code; -pub use self::module::{module, ModuleBuilder}; \ No newline at end of file +pub use self::module::{module, ModuleBuilder}; +pub use self::code::function; \ No newline at end of file diff --git a/src/builder/module.rs b/src/builder/module.rs index 1cec56b..898b4c4 100644 --- a/src/builder/module.rs +++ b/src/builder/module.rs @@ -1,11 +1,57 @@ use super::invoke::{Invoke, Identity}; -use super::code::FunctionsBuilder; +use super::code::{self, FunctionsBuilder}; use elements; /// Module builder pub struct ModuleBuilder { callback: F, - sections: Vec, + module: ModuleScaffold, +} + +#[derive(Default)] +struct ModuleScaffold { + pub functions: elements::FunctionsSection, + pub types: elements::TypeSection, + pub other: Vec, +} + +impl From for ModuleScaffold { + fn from(module: elements::Module) -> Self { + let mut funcs: Option = None; + let mut types: Option = None; + + 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); } + _ => {} + } + } + + ModuleScaffold { + functions: funcs.unwrap_or_default(), + types: types.unwrap_or_default(), + other: sections, + } + } +} + +impl From 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)); + } + sections.extend(module.other); + elements::Module::new(sections) + } } impl ModuleBuilder { @@ -20,7 +66,7 @@ impl ModuleBuilder where F: Invoke { pub fn with_callback(callback: F) -> Self { ModuleBuilder { callback: callback, - sections: Vec::new(), + module: Default::default(), } } @@ -28,22 +74,51 @@ impl ModuleBuilder where F: Invoke { pub fn with_sections(mut self, sections: I) -> Self where I: IntoIterator { - self.sections.extend(sections); + self.module.other.extend(sections); self } + /// Add additional section pub fn with_section(mut self, section: elements::Section) -> Self { - self.sections.push(section); + self.module.other.push(section); self } + /// Binds to the type section, creates additional types when required + pub fn with_signatures(mut self, bindings: code::SignatureBindings) -> Self { + // todo bind to type section + + { + let module = &mut self.module; + + let raw_functions: Vec = bindings.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 + } + } + ).collect(); + + for function in raw_functions { + module.functions.entries_mut().push(elements::Func::new(function)); + } + } + + self + } + + /// Define functions section pub fn functions(self) -> FunctionsBuilder { FunctionsBuilder::with_callback(self) } /// Build module (final step) pub fn build(self) -> F::Result { - self.callback.invoke(elements::Module::new(self.sections)) + self.callback.invoke(self.module.into()) } } @@ -57,6 +132,16 @@ impl Invoke for ModuleBuilder } } +impl Invoke for ModuleBuilder + where F: Invoke +{ + type Result = Self; + + fn invoke(self, bindings: code::SignatureBindings) -> Self { + self.with_signatures(bindings) + } +} + /// Start new module builder pub fn module() -> ModuleBuilder { ModuleBuilder::new() @@ -73,4 +158,16 @@ mod tests { assert_eq!(module.sections().len(), 0); } + #[test] + fn functions() { + let module = module() + .functions() + .signature().param(::elements::ValueType::I32).build() + .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); + } + } diff --git a/src/elements/mod.rs b/src/elements/mod.rs index 77a3f8c..f003623 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -16,7 +16,7 @@ mod segment; pub use self::module::Module; pub use self::section::{ Section, FunctionsSection, CodeSection, MemorySection, DataSection, - ImportSection, ExportSection, GlobalSection, + ImportSection, ExportSection, GlobalSection, TypeSection, }; pub use self::import_entry::{ImportEntry, MemoryType, TableType, GlobalType, External}; pub use self::export_entry::{ExportEntry, Internal}; @@ -25,7 +25,7 @@ pub use self::primitives::{ VarUint32, VarUint7, VarUint1, VarInt7, Uint32, Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter, }; -pub use self::types::{ValueType, BlockType, FunctionType}; +pub use self::types::{Type, ValueType, BlockType, FunctionType}; pub use self::ops::{Opcode, Opcodes, InitExpr}; pub use self::func::{Func, FuncBody, Local}; pub use self::segment::{ElementSegment, DataSegment}; @@ -121,4 +121,11 @@ pub fn serialize(val: T) -> Result, T::Error> { let mut buf = Vec::new(); val.serialize(&mut buf)?; Ok(buf) +} + +/// Serialize module to the file +pub fn serialize_to_file>(p: P, module: Module) -> Result<(), Error> +{ + let mut io = ::std::fs::File::create(p)?; + module.serialize(&mut io) } \ No newline at end of file diff --git a/src/elements/module.rs b/src/elements/module.rs index ecbcd28..2b37c0f 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -1,6 +1,6 @@ use std::io; use super::{Deserialize, Serialize, Error, Uint32}; -use super::section::{Section, CodeSection, TypeSection, ImportSection}; +use super::section::{Section, CodeSection, TypeSection, ImportSection, FunctionsSection}; /// WebAssembly module pub struct Module { @@ -9,16 +9,29 @@ pub struct Module { sections: Vec
, } +impl Default for Module { + fn default() -> Self { + Module { + magic: 0x6d736100, + version: 1, + sections: Vec::with_capacity(16), + } + } +} + impl Module { /// New module with sections pub fn new(sections: Vec
) -> Self { Module { - magic: 0x6d736100, - version: 1, - sections: sections, + sections: sections, ..Default::default() } } + /// Destructure the module, yielding sections + pub fn into_sections(self) -> Vec
{ + self.sections + } + /// Version of module. pub fn version(&self) -> u32 { self.version } @@ -57,6 +70,14 @@ impl Module { } None } + + /// Functions signatures section, if any. + pub fn functions_section(&self) -> Option<&FunctionsSection> { + for section in self.sections() { + if let &Section::Function(ref sect) = section { return Some(sect); } + } + None + } } impl Deserialize for Module { diff --git a/src/elements/section.rs b/src/elements/section.rs index 54a06c0..8fb6438 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -176,12 +176,20 @@ impl Serialize for Section { } } +/// Section with type declarations +#[derive(Default)] pub struct TypeSection(Vec); impl TypeSection { + /// List of type declarations pub fn types(&self) -> &[Type] { &self.0 } + + /// List of type declarations (mutable) + pub fn types_mut(&mut self) -> &mut Vec { + &mut self.0 + } } impl Deserialize for TypeSection { @@ -215,6 +223,7 @@ impl Serialize for TypeSection { pub struct ImportSection(Vec); impl ImportSection { + /// List of import entries. pub fn entries(&self) -> &[ImportEntry] { &self.0 } @@ -248,17 +257,21 @@ impl Serialize for ImportSection { } /// Section with function signatures definition. +#[derive(Default)] pub struct FunctionsSection(Vec); impl FunctionsSection { + /// New functions section pub fn new() -> FunctionsSection { FunctionsSection(Vec::new()) } + /// List of all functions in the section, mutable pub fn entries_mut(&mut self) -> &mut Vec { &mut self.0 } + /// List of all functions in the section pub fn entries(&self) -> &[Func] { &self.0 } @@ -335,6 +348,7 @@ impl Serialize for TableSection { pub struct MemorySection(Vec); impl MemorySection { + /// List of all memory entries in the section pub fn entries(&self) -> &[MemoryType] { &self.0 } @@ -371,6 +385,7 @@ impl Serialize for MemorySection { pub struct GlobalSection(Vec); impl GlobalSection { + /// List of all global entries in the section pub fn entries(&self) -> &[GlobalEntry] { &self.0 } @@ -407,6 +422,7 @@ impl Serialize for GlobalSection { pub struct ExportSection(Vec); impl ExportSection { + /// List of all export entries in the section pub fn entries(&self) -> &[ExportEntry] { &self.0 } @@ -443,10 +459,12 @@ impl Serialize for ExportSection { pub struct CodeSection(Vec); impl CodeSection { + /// New code section pub fn new(bodies: Vec) -> Self { CodeSection(bodies) } + /// All function bodies in the section pub fn bodies(&self) -> &[FuncBody] { &self.0 } @@ -483,10 +501,12 @@ impl Serialize for CodeSection { pub struct ElementSection(Vec); impl ElementSection { + /// New elements section pub fn new(entries: Vec) -> Self { ElementSection(entries) } + /// New elements entries in the section pub fn entries(&self) -> &[ElementSegment] { &self.0 } @@ -523,10 +543,12 @@ impl Serialize for ElementSection { pub struct DataSection(Vec); impl DataSection { + /// New data section pub fn new(segments: Vec) -> Self { DataSection(segments) } + /// List of all data entries in the section pub fn entries(&self) -> &[DataSegment] { &self.0 } diff --git a/src/elements/types.rs b/src/elements/types.rs index ac40061..e034f85 100644 --- a/src/elements/types.rs +++ b/src/elements/types.rs @@ -132,6 +132,14 @@ impl Default for FunctionType { } impl FunctionType { + /// New function type given the signature in-params(`params`) and return type (`return_type`) + pub fn new(params: Vec, return_type: Option) -> Self { + FunctionType { + params: params, + return_type: return_type, + ..Default::default() + } + } /// Function form (currently only valid value is `0x60`) pub fn form(&self) -> u8 { self.form } /// Parameters in the function signature. diff --git a/src/lib.rs b/src/lib.rs index 690bdcb..b5f2918 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,5 +10,7 @@ pub mod builder; pub use elements::{ Error as SerializationError, deserialize_buffer, - deserialize_file + deserialize_file, + serialize, + serialize_to_file, };