diff --git a/src/builder/code.rs b/src/builder/code.rs new file mode 100644 index 0000000..a2dd102 --- /dev/null +++ b/src/builder/code.rs @@ -0,0 +1,141 @@ +use super::invoke::{Invoke, Identity}; +use elements; + +pub enum Signature { + TypeReference(u32), + Inline(elements::FunctionType), +} + +pub struct SignatureBuilder { + callback: F, + signature: Signature, +} + +impl SignatureBuilder where F: Invoke { + pub fn with_callback(callback: F) -> Self { + SignatureBuilder { + callback: callback, + signature: Signature::TypeReference(0) + } + } + + 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 + } + + 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 + } + + pub fn build(self) -> F::Result { + self.callback.invoke(self.signature) + } +} + +pub struct FunctionsBuilder { + callback: F, + section: Vec, +} + +impl FunctionsBuilder { + /// New empty functions section builder + pub fn new() -> Self { + FunctionsBuilder::with_callback(Identity) + } +} + +impl FunctionsBuilder { + pub fn with_callback(callback: F) -> Self { + FunctionsBuilder { + callback: callback, + section: Vec::new(), + } + } + + pub fn with_signature(mut self, signature: Signature) -> Self { + self.section.push(signature); + self + } + + pub fn signature(self) -> SignatureBuilder { + SignatureBuilder::with_callback(self) + } +} + +impl Invoke for FunctionsBuilder { + type Result = Self; + + fn invoke(self, signature: Signature) -> Self { + self.with_signature(signature) + } +} + +impl FunctionsBuilder where F: Invoke { + pub fn build(self) -> F::Result { + let mut result = elements::FunctionsSection::new(); + for f in self.section.into_iter() { + if let Signature::TypeReference(type_ref) = f { + result.entries_mut().push(elements::Func::new(type_ref)); + } else { + unreachable!(); // never possible with current generics impl-s + } + } + self.callback.invoke(result) + } +} + +pub type SignatureBindings = Vec; + +impl FunctionsBuilder where F: Invoke { + pub fn bind(self) -> F::Result { + self.callback.invoke(self.section) + } +} + +#[cfg(test)] +mod tests { + + use super::FunctionsBuilder; + + #[test] + fn example() { + let result = FunctionsBuilder::new() + .signature().type_ref(1).build() + .build(); + + assert_eq!(result.entries().len(), 1); + + let result = FunctionsBuilder::new() + .signature().type_ref(1).build() + .bind(); + + assert_eq!(result.len(), 1); + } +} \ No newline at end of file diff --git a/src/builder/invoke.rs b/src/builder/invoke.rs new file mode 100644 index 0000000..6fe8bdb --- /dev/null +++ b/src/builder/invoke.rs @@ -0,0 +1,15 @@ +//! invoke helper + +pub trait Invoke { + type Result; + + fn invoke(self, arg: A) -> Self::Result; +} + +pub struct Identity; + +impl Invoke for Identity { + type Result = A; + + fn invoke(self, arg: A) -> A { arg } +} \ No newline at end of file diff --git a/src/builder/mod.rs b/src/builder/mod.rs new file mode 100644 index 0000000..f41fd90 --- /dev/null +++ b/src/builder/mod.rs @@ -0,0 +1,7 @@ +//! Various builders to generate/alter wasm components + +mod invoke; +mod module; +mod code; + +pub use self::module::{module, ModuleBuilder}; \ No newline at end of file diff --git a/src/builder/module.rs b/src/builder/module.rs new file mode 100644 index 0000000..1cec56b --- /dev/null +++ b/src/builder/module.rs @@ -0,0 +1,76 @@ +use super::invoke::{Invoke, Identity}; +use super::code::FunctionsBuilder; +use elements; + +/// Module builder +pub struct ModuleBuilder { + callback: F, + sections: Vec, +} + +impl ModuleBuilder { + /// New empty module builder + pub fn new() -> Self { + ModuleBuilder::with_callback(Identity) + } +} + +impl ModuleBuilder where F: Invoke { + /// New module builder with bound callback + pub fn with_callback(callback: F) -> Self { + ModuleBuilder { + callback: callback, + sections: Vec::new(), + } + } + + /// Fill module with sections from iterator + pub fn with_sections(mut self, sections: I) -> Self + where I: IntoIterator + { + self.sections.extend(sections); + self + } + + pub fn with_section(mut self, section: elements::Section) -> Self { + self.sections.push(section); + self + } + + 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)) + } +} + +impl Invoke for ModuleBuilder + where F: Invoke +{ + type Result = Self; + + fn invoke(self, section: elements::FunctionsSection) -> Self { + self.with_section(elements::Section::Function(section)) + } +} + +/// 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); + } + +} diff --git a/src/elements/mod.rs b/src/elements/mod.rs index b798c7b..77a3f8c 100644 --- a/src/elements/mod.rs +++ b/src/elements/mod.rs @@ -14,7 +14,10 @@ mod func; mod segment; pub use self::module::Module; -pub use self::section::Section; +pub use self::section::{ + Section, FunctionsSection, CodeSection, MemorySection, DataSection, + ImportSection, ExportSection, GlobalSection, +}; pub use self::import_entry::{ImportEntry, MemoryType, TableType, GlobalType, External}; pub use self::export_entry::{ExportEntry, Internal}; pub use self::global_entry::GlobalEntry; @@ -22,7 +25,7 @@ pub use self::primitives::{ VarUint32, VarUint7, VarUint1, VarInt7, Uint32, Uint64, VarUint64, CountedList, CountedWriter, CountedListWriter, }; -pub use self::types::{ValueType, BlockType}; +pub use self::types::{ValueType, BlockType, FunctionType}; pub use self::ops::{Opcode, Opcodes, InitExpr}; pub use self::func::{Func, FuncBody, Local}; pub use self::segment::{ElementSegment, DataSegment}; diff --git a/src/elements/module.rs b/src/elements/module.rs index 29a7d50..ecbcd28 100644 --- a/src/elements/module.rs +++ b/src/elements/module.rs @@ -10,6 +10,15 @@ pub struct Module { } impl Module { + /// New module with sections + pub fn new(sections: Vec
) -> Self { + Module { + magic: 0x6d736100, + version: 1, + sections: sections, + } + } + /// Version of module. pub fn version(&self) -> u32 { self.version } diff --git a/src/elements/section.rs b/src/elements/section.rs index 693a6b0..54a06c0 100644 --- a/src/elements/section.rs +++ b/src/elements/section.rs @@ -251,6 +251,14 @@ impl Serialize for ImportSection { pub struct FunctionsSection(Vec); impl FunctionsSection { + pub fn new() -> FunctionsSection { + FunctionsSection(Vec::new()) + } + + pub fn entries_mut(&mut self) -> &mut Vec { + &mut self.0 + } + pub fn entries(&self) -> &[Func] { &self.0 } diff --git a/src/elements/types.rs b/src/elements/types.rs index 9709407..ac40061 100644 --- a/src/elements/types.rs +++ b/src/elements/types.rs @@ -121,13 +121,27 @@ pub struct FunctionType { return_type: Option, } +impl Default for FunctionType { + fn default() -> Self { + FunctionType { + form: 0x60, + params: Vec::new(), + return_type: None, + } + } +} + impl FunctionType { /// Function form (currently only valid value is `0x60`) pub fn form(&self) -> u8 { self.form } /// Parameters in the function signature. pub fn params(&self) -> &[ValueType] { &self.params } + /// Mutable parameters in the function signature. + pub fn params_mut(&mut self) -> &mut Vec { &mut self.params } /// Return type in the function signature, if any. pub fn return_type(&self) -> Option { self.return_type } + /// Mutable type in the function signature, if any. + pub fn return_type_mut(&mut self) -> &mut Option { &mut self.return_type } } impl Deserialize for FunctionType { diff --git a/src/lib.rs b/src/lib.rs index 0263ff2..690bdcb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ extern crate byteorder; pub mod elements; +pub mod builder; pub use elements::{ Error as SerializationError,