sophon_wasm/builder/
module.rs

1use super::invoke::{Invoke, Identity};
2use super::code::{self, SignaturesBuilder, FunctionBuilder};
3use super::memory::{self, MemoryBuilder};
4use super::table::{self, TableBuilder};
5use super::{import, export, global, data};
6use elements;
7
8/// Module builder
9pub struct ModuleBuilder<F=Identity> {
10    callback: F,
11    module: ModuleScaffold,
12}
13
14/// Location of the internal module function
15pub struct CodeLocation {
16    /// Location (index in 'functions' section) of the signature
17    pub signature: u32,
18    /// Location (index in the 'code' section) of the body
19    pub body: u32,
20}
21
22#[derive(Default)]
23struct ModuleScaffold {
24    pub types: elements::TypeSection,
25    pub import: elements::ImportSection,
26    pub functions: elements::FunctionSection,
27    pub table: elements::TableSection,
28    pub memory: elements::MemorySection,
29    pub global: elements::GlobalSection,
30    pub export: elements::ExportSection,
31    pub start: Option<u32>,
32    pub element: elements::ElementSection,
33    pub code: elements::CodeSection,
34    pub data: elements::DataSection,
35    pub other: Vec<elements::Section>,
36}
37
38impl From<elements::Module> for ModuleScaffold {
39    fn from(module: elements::Module) -> Self {
40        let mut types: Option<elements::TypeSection> = None;
41        let mut import: Option<elements::ImportSection> = None;
42        let mut funcs: Option<elements::FunctionSection> = None;
43        let mut table: Option<elements::TableSection> = None;
44        let mut memory: Option<elements::MemorySection> = None;
45        let mut global: Option<elements::GlobalSection> = None;
46        let mut export: Option<elements::ExportSection> = None;
47        let mut start: Option<u32> = None;
48        let mut element: Option<elements::ElementSection> = None;
49        let mut code: Option<elements::CodeSection> = None;
50        let mut data: Option<elements::DataSection> = None;
51
52        let mut sections = module.into_sections();
53        while let Some(section) = sections.pop() {
54            match section {
55                elements::Section::Type(sect) => { types = Some(sect); }
56                elements::Section::Import(sect) => { import = Some(sect); }
57                elements::Section::Function(sect) => { funcs = Some(sect); }
58                elements::Section::Table(sect) => { table = Some(sect); }
59                elements::Section::Memory(sect) => { memory = Some(sect); }
60                elements::Section::Global(sect) => { global = Some(sect); }
61                elements::Section::Export(sect) => { export = Some(sect); }
62                elements::Section::Start(index) => { start = Some(index); }
63                elements::Section::Element(sect) => { element = Some(sect); }
64                elements::Section::Code(sect) => { code = Some(sect); }
65                elements::Section::Data(sect) => { data = Some(sect); }
66                _ => {}
67            }
68        }
69
70        ModuleScaffold {
71            types: types.unwrap_or_default(),
72            import: import.unwrap_or_default(),
73            functions: funcs.unwrap_or_default(),
74            table: table.unwrap_or_default(),
75            memory: memory.unwrap_or_default(),
76            global: global.unwrap_or_default(),
77            export: export.unwrap_or_default(),
78            start: start,
79            element: element.unwrap_or_default(),
80            code: code.unwrap_or_default(),
81            data: data.unwrap_or_default(),
82            other: sections,
83        }
84    }
85}
86
87impl From<ModuleScaffold> for elements::Module {
88    fn from(module: ModuleScaffold) -> Self {
89        let mut sections = Vec::new();
90
91        let types = module.types;
92        if types.types().len() > 0 {
93            sections.push(elements::Section::Type(types));
94        }
95        let import = module.import;
96        if import.entries().len() > 0 {
97            sections.push(elements::Section::Import(import));
98        }                
99        let functions = module.functions;
100        if functions.entries().len() > 0 {
101            sections.push(elements::Section::Function(functions));
102        }
103        let table = module.table;
104        if table.entries().len() > 0 {
105            sections.push(elements::Section::Table(table));
106        }
107        let memory = module.memory;
108        if memory.entries().len() > 0 {
109            sections.push(elements::Section::Memory(memory));
110        }
111        let global = module.global;
112        if global.entries().len() > 0 {
113            sections.push(elements::Section::Global(global));
114        }
115        let export = module.export;
116        if export.entries().len() > 0 {
117            sections.push(elements::Section::Export(export));
118        }
119        if let Some(start) = module.start {
120            sections.push(elements::Section::Start(start));
121        }
122        let element = module.element;
123        if element.entries().len() > 0 {
124            sections.push(elements::Section::Element(element));
125        }
126        let code = module.code;
127        if code.bodies().len() > 0 {
128            sections.push(elements::Section::Code(code));
129        }
130        let data = module.data;
131        if data.entries().len() > 0 {
132            sections.push(elements::Section::Data(data));
133        }
134        sections.extend(module.other);
135        elements::Module::new(sections)
136    }
137}
138
139impl ModuleBuilder {
140    /// New empty module builder
141    pub fn new() -> Self {
142        ModuleBuilder::with_callback(Identity)
143    }
144}
145
146impl<F> ModuleBuilder<F> where F: Invoke<elements::Module> {
147    /// New module builder with bound callback
148    pub fn with_callback(callback: F) -> Self {
149        ModuleBuilder {
150            callback: callback,
151            module: Default::default(),
152        }
153    }
154
155    /// Builder from raw module
156    pub fn with_module(mut self, module: elements::Module) -> Self {
157        self.module = module.into();
158        self
159    }
160
161    /// Fill module with sections from iterator
162    pub fn with_sections<I>(mut self, sections: I) -> Self 
163        where I: IntoIterator<Item=elements::Section>
164    {
165        self.module.other.extend(sections);
166        self
167    }
168
169    /// Add additional section
170    pub fn with_section(mut self, section: elements::Section) -> Self {
171        self.module.other.push(section);
172        self
173    }
174
175    /// Binds to the type section, creates additional types when required
176    pub fn with_signatures(mut self, bindings: code::SignatureBindings) -> Self {
177        self.push_signatures(bindings);
178        self
179    }
180
181    /// Push stand-alone function definition, creating sections, signature and code blocks
182    /// in corresponding sections.
183    /// `FunctionDefinition` can be build using `builder::function` builder
184    pub fn push_function(&mut self, func: code::FunctionDefinition) -> CodeLocation {
185        let signature = func.signature;
186        let body = func.code;
187
188        let type_ref = self.resolve_type_ref(signature);
189
190        self.module.functions.entries_mut().push(elements::Func::new(type_ref));
191        let signature_index = self.module.functions.entries_mut().len() as u32 - 1;
192        self.module.code.bodies_mut().push(body);
193        let body_index = self.module.code.bodies_mut().len() as u32 - 1;
194
195        if func.is_main {
196            self.module.start = Some(body_index);
197        }
198
199        CodeLocation {
200            signature: signature_index,
201            body: body_index,
202        }
203    }
204
205    /// Push linear memory region
206    pub fn push_memory(&mut self, mut memory: memory::MemoryDefinition) -> u32 {
207        let entries = self.module.memory.entries_mut();
208        entries.push(elements::MemoryType::new(memory.min, memory.max));
209        let memory_index = (entries.len() - 1) as u32;
210        for data in memory.data.drain(..) {
211            self.module.data.entries_mut()
212                .push(elements::DataSegment::new(memory_index, data.offset, data.values))
213        }
214        memory_index
215    }
216
217    /// Push table
218    pub fn push_table(&mut self, mut table: table::TableDefinition) -> u32 {
219        let entries = self.module.table.entries_mut();
220        entries.push(elements::TableType::new(table.min, table.max));
221        let table_index = (entries.len() - 1) as u32;
222        for entry in table.elements.drain(..) {
223            self.module.element.entries_mut()
224                .push(elements::ElementSegment::new(table_index, entry.offset, entry.values))
225        }
226        table_index
227    }
228
229    fn resolve_type_ref(&mut self, signature: code::Signature) -> u32 {
230        match signature {
231            code::Signature::Inline(func_type) => {
232                // todo: maybe search for existing type
233                self.module.types.types_mut().push(elements::Type::Function(func_type));
234                self.module.types.types().len() as u32 - 1
235            }
236            code::Signature::TypeReference(type_ref) => {
237                type_ref
238            }
239        }
240    }
241
242    /// Push one function signature, returning it's calling index.
243    /// Can create corresponding type in type section.
244    pub fn push_signature(&mut self, signature: code::Signature) -> u32 {
245        self.resolve_type_ref(signature)
246    }
247
248    /// Push signatures in the module, returning corresponding indices of pushed signatures
249    pub fn push_signatures(&mut self, signatures: code::SignatureBindings) -> Vec<u32> {
250        signatures.into_iter().map(|binding|
251            self.resolve_type_ref(binding)
252        ).collect()
253    }
254
255    /// Push import entry to module. Not that it does not update calling indices in
256    /// function bodies.
257    pub fn push_import(&mut self, import: elements::ImportEntry) -> u32 {
258        self.module.import.entries_mut().push(import);
259        // todo: actually update calling addresses in function bodies
260        // todo: also batch push
261
262        self.module.import.entries_mut().len() as u32 - 1
263    }
264
265    /// Push export entry to module. 
266    pub fn push_export(&mut self, export: elements::ExportEntry) -> u32 {
267        self.module.export.entries_mut().push(export);
268        self.module.export.entries_mut().len() as u32 - 1
269    }
270
271    /// Add new function using dedicated builder
272    pub fn function(self) -> FunctionBuilder<Self> {
273        FunctionBuilder::with_callback(self)
274    }
275
276    /// Add new linear memory using dedicated builder
277    pub fn memory(self) -> MemoryBuilder<Self> {
278        MemoryBuilder::with_callback(self)
279    }
280
281    /// Add new table using dedicated builder
282    pub fn table(self) -> TableBuilder<Self> {
283        TableBuilder::with_callback(self)
284    }
285
286    /// Define functions section
287    pub fn functions(self) -> SignaturesBuilder<Self> {
288        SignaturesBuilder::with_callback(self)
289    }
290
291    /// With inserted export entry
292    pub fn with_export(mut self, entry: elements::ExportEntry) -> Self {
293        self.module.export.entries_mut().push(entry);
294        self
295    }
296
297    /// With inserted import entry
298    pub fn with_import(mut self, entry: elements::ImportEntry) -> Self {
299        self.module.import.entries_mut().push(entry);
300        self
301    }
302
303    /// Import entry builder
304    /// # Examples
305    /// ```
306    /// use sophon_wasm::builder::module;
307    ///
308    /// let module = module()
309    ///    .import()
310    ///        .module("env")
311    ///        .field("memory")
312    ///        .external().memory(256, Some(256))
313    ///        .build()
314    ///    .build();
315    ///
316    /// assert_eq!(module.import_section().expect("import section to exist").entries().len(), 1);
317    /// ```
318    pub fn import(self) -> import::ImportBuilder<Self> {
319        import::ImportBuilder::with_callback(self)
320    }
321
322    /// With global variable
323    pub fn with_global(mut self, global: elements::GlobalEntry) -> Self {
324        self.module.global.entries_mut().push(global);
325        self
326    }
327
328    /// With table
329    pub fn with_table(mut self, table: elements::TableType) -> Self {
330        self.module.table.entries_mut().push(table);
331        self
332    }
333
334    /// Export entry builder
335    /// # Examples
336    /// ```
337    /// use sophon_wasm::builder::module;
338    /// use sophon_wasm::elements::Opcode::*;
339    ///
340    /// let module = module()
341    ///    .global()
342    ///         .value_type().i32()
343    ///         .init_expr(I32Const(0))
344    ///         .build()
345    ///    .export()
346    ///        .field("_zero")
347    ///        .internal().global(0)
348    ///        .build()
349    ///    .build();
350    ///
351    /// assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1);
352    /// ```    
353    pub fn export(self) -> export::ExportBuilder<Self> {
354        export::ExportBuilder::with_callback(self)
355    }
356
357    /// Glboal entry builder
358    /// # Examples
359    /// ```
360    /// use sophon_wasm::builder::module;
361    /// use sophon_wasm::elements::Opcode::*;
362    ///
363    /// let module = module()
364    ///    .global()
365    ///         .value_type().i32()
366    ///         .init_expr(I32Const(0))
367    ///         .build()
368    ///    .build();
369    ///
370    /// assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1);
371    /// ```        
372    pub fn global(self) -> global::GlobalBuilder<Self> {
373        global::GlobalBuilder::with_callback(self)
374    }
375
376    /// Add data segment to the builder
377    pub fn with_data_segment(mut self, segment: elements::DataSegment) -> Self {
378        self.module.data.entries_mut().push(segment);
379        self
380    }
381
382    /// Data entry builder
383    pub fn data(self) -> data::DataSegmentBuilder<Self> {
384        data::DataSegmentBuilder::with_callback(self)
385    }
386
387    /// Build module (final step)
388    pub fn build(self) -> F::Result {
389        self.callback.invoke(self.module.into())
390    }
391}
392
393impl<F> Invoke<elements::FunctionSection> for ModuleBuilder<F> 
394    where F: Invoke<elements::Module>
395{
396	type Result = Self;
397
398	fn invoke(self, section: elements::FunctionSection) -> Self {
399		self.with_section(elements::Section::Function(section))
400    }    
401}
402
403impl<F> Invoke<code::SignatureBindings> for ModuleBuilder<F>
404    where F: Invoke<elements::Module> 
405{
406    type Result = Self;
407
408    fn invoke(self, bindings: code::SignatureBindings) -> Self {
409        self.with_signatures(bindings)
410    }
411}
412
413
414impl<F> Invoke<code::FunctionDefinition> for ModuleBuilder<F>
415    where F: Invoke<elements::Module> 
416{
417    type Result = Self;
418
419    fn invoke(self, def: code::FunctionDefinition) -> Self {
420        let mut b = self;
421        b.push_function(def);
422        b
423    }
424}
425
426impl<F> Invoke<memory::MemoryDefinition> for ModuleBuilder<F>
427    where F: Invoke<elements::Module> 
428{
429    type Result = Self;
430
431    fn invoke(self, def: memory::MemoryDefinition) -> Self {
432        let mut b = self;
433        b.push_memory(def);
434        b
435    }
436}
437
438impl<F> Invoke<table::TableDefinition> for ModuleBuilder<F>
439    where F: Invoke<elements::Module> 
440{
441    type Result = Self;
442
443    fn invoke(self, def: table::TableDefinition) -> Self {
444        let mut b = self;
445        b.push_table(def);
446        b
447    }
448}
449
450impl<F> Invoke<elements::ImportEntry> for ModuleBuilder<F>
451    where F: Invoke<elements::Module> 
452{
453    type Result = Self;
454
455    fn invoke(self, entry: elements::ImportEntry) -> Self::Result {
456        self.with_import(entry)
457    }
458}
459
460impl<F> Invoke<elements::ExportEntry> for ModuleBuilder<F>
461    where F: Invoke<elements::Module> 
462{
463    type Result = Self;
464
465    fn invoke(self, entry: elements::ExportEntry) -> Self::Result {
466        self.with_export(entry)
467    }
468}
469
470impl<F> Invoke<elements::GlobalEntry> for ModuleBuilder<F>
471    where F: Invoke<elements::Module> 
472{
473    type Result = Self;
474
475    fn invoke(self, entry: elements::GlobalEntry) -> Self::Result {
476        self.with_global(entry)
477    }
478}
479
480impl<F> Invoke<elements::DataSegment> for ModuleBuilder<F> 
481    where F: Invoke<elements::Module>
482{
483	type Result = Self;
484
485	fn invoke(self, segment: elements::DataSegment) -> Self {
486		self.with_data_segment(segment)
487    }    
488}
489
490/// Start new module builder
491/// # Examples
492///
493/// ```
494/// use sophon_wasm::builder;
495/// 
496/// let module = builder::module()
497///     .function()
498///         .signature().param().i32().build()
499///         .body().build()
500///         .build()
501///     .build();
502///
503/// assert_eq!(module.type_section().expect("type section to exist").types().len(), 1);
504/// assert_eq!(module.function_section().expect("function section to exist").entries().len(), 1);
505/// assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1);
506/// ```
507pub fn module() -> ModuleBuilder {
508    ModuleBuilder::new()
509}
510
511/// Start builder to extend existing module
512pub fn from_module(module: elements::Module) -> ModuleBuilder {
513    ModuleBuilder::new().with_module(module)
514}
515
516#[cfg(test)]
517mod tests {
518
519    use super::module;
520
521    #[test]
522    fn smoky() {
523        let module = module().build();
524        assert_eq!(module.sections().len(), 0);
525    }
526
527    #[test]
528    fn functions() {
529        let module = module()
530            .function()
531                .signature().param().i32().build()
532                .body().build()
533                .build()
534            .build();
535
536        assert_eq!(module.type_section().expect("type section to exist").types().len(), 1);
537        assert_eq!(module.function_section().expect("function section to exist").entries().len(), 1);
538        assert_eq!(module.code_section().expect("code section to exist").bodies().len(), 1);
539    }
540
541    #[test]
542    fn export() {
543        let module = module()
544            .export().field("call").internal().func(0).build()
545            .build();
546
547        assert_eq!(module.export_section().expect("export section to exist").entries().len(), 1);
548    }
549
550    #[test]
551    fn global() {
552        let module = module()
553            .global().value_type().i64().mutable().init_expr(::elements::Opcode::I64Const(5)).build()
554            .build();
555
556        assert_eq!(module.global_section().expect("global section to exist").entries().len(), 1);        
557    }
558
559    #[test]
560    fn data() {
561        let module = module()
562            .data()
563                .offset(::elements::Opcode::I32Const(16))
564                .value(vec![0u8, 15, 10, 5, 25])
565                .build()
566            .build();
567
568        assert_eq!(module.data_section().expect("data section to exist").entries().len(), 1);
569    }
570 }