makepad_wasm_bridge/
to_wasm.rs

1use makepad_live_id::*;
2use crate::from_wasm::*;
3
4pub struct WasmJSOutputFn{
5    pub name: String,
6    pub body: String,
7    pub temp: usize
8}
9
10pub struct WasmJSOutput{
11    pub temp_alloc: usize,
12    pub fns: Vec<WasmJSOutputFn>,
13}
14
15impl WasmJSOutput{
16    pub fn alloc_temp(&mut self)->usize{
17       self.temp_alloc += 1;
18       self.temp_alloc 
19    }
20    
21    pub fn check_slot(&mut self, slot:usize, is_recur:bool, prop:&str, temp:usize, name:&str)->Option<usize>{
22        // ok so if we recur
23        if is_recur{ // call body
24            self.push_ln(slot, &format!("{}({});", name, prop));
25            // check if we already have the fn
26            if self.fns.iter().any(|p| p.name == name){
27                return None
28            }
29            self.fns.push(WasmJSOutputFn{name: name.to_string(), body:String::new(), temp});
30            Some(self.fns.len() - 1)
31        }
32        else{
33            self.push_ln(slot, &format!("let t{} = {};", temp, prop));
34            Some(slot)
35        }
36    }
37    
38    pub fn push_ln(&mut self, slot:usize, s:&str){
39        self.fns[slot].body.push_str(s);
40        self.fns[slot].body.push('\n');
41    }
42}
43
44pub trait ToWasm {
45    fn u32_size() -> usize;
46    
47    fn type_name()->&'static str{panic!()}
48    fn live_id()->LiveId{panic!()}
49
50    fn read_to_wasm(inp: &mut ToWasmMsgRef) -> Self;
51    
52    fn to_wasm_js_body(out: &mut WasmJSOutput, slot:usize, is_recur: bool, prop:&str, temp:usize);
53    
54    fn to_js_code()->String{
55        let mut wrapper = String::new();
56        let id = Self::live_id();
57        wrapper.push_str(&format!("{}(t0){{\n", Self::type_name()));
58        wrapper.push_str("let app = this.app;\n");
59        wrapper.push_str(&format!("this.reserve_u32({});\n", 4 + Self::u32_size()));
60        wrapper.push_str(&format!("app.u32[this.u32_offset ++] = {};\n", id.0 & 0xffff_ffff));
61        wrapper.push_str(&format!("app.u32[this.u32_offset ++] = {};\n", (id.0 >> 32)));
62        wrapper.push_str("let block_len_offset = this.u32_offset ++;\n\n");
63        
64        let mut out = WasmJSOutput{temp_alloc:0, fns:vec![WasmJSOutputFn{name:String::new(), body:String::new(), temp:0}]};
65        
66        let new_temp = out.alloc_temp();
67        Self::to_wasm_js_body(&mut out, 0, false, "t0", new_temp);
68
69        for p in out.fns.iter().rev(){
70            if p.name.is_empty(){
71                wrapper.push_str(&p.body);
72            }
73            else{
74                wrapper.push_str(&format!("let {} = (t{})=>{{\n{}}}\n", p.name, p.temp, p.body))
75            }
76        }
77        
78        wrapper.push_str("if( (this.u32_offset & 1) != 0){ app.u32[this.u32_offset ++] = 0;}\n");
79        wrapper.push_str("let new_len = (this.u32_offset - this.u32_ptr) >> 1;\n");
80        wrapper.push_str("app.u32[block_len_offset] = new_len - app.u32[this.u32_ptr + 1];\n");
81        wrapper.push_str("app.u32[this.u32_ptr + 1] = new_len;\n");
82        wrapper.push_str("}\n");
83        wrapper
84    }
85}
86
87#[derive(Clone, Default, Debug)]
88pub struct ToWasmMsg {
89    data: Vec<u64>,
90}
91
92pub struct ToWasmBlockSkip{
93    len:usize,
94    base:usize
95}
96
97#[derive(Clone, Default, Debug)]
98pub struct ToWasmMsgRef<'a> {
99    data: &'a[u64],
100    pub u32_offset: usize
101}
102
103impl ToWasmMsg {
104    
105    pub fn take_ownership(val: u32) -> Self {
106        unsafe {
107            let ptr = val as *mut u64;
108            let head = ptr.offset(0).read();
109            let len = (head >> 32) as usize;
110            let cap = (head & 0xffff_ffff) as usize;
111            
112            Self {
113                data: Vec::from_raw_parts(ptr, len, cap),
114                //u32_offset: 2,
115            }
116        }
117    }
118    
119    pub fn into_from_wasm(self) -> FromWasmMsg {
120        FromWasmMsg {
121            data: self.data,
122            odd: false
123        }
124    }
125    
126    pub fn as_ref(&self) ->ToWasmMsgRef{
127        ToWasmMsgRef{
128            data: &self.data,
129            u32_offset: 2
130        }
131    }
132    
133    pub fn as_ref_at(&self, offset:usize) ->ToWasmMsgRef{
134        ToWasmMsgRef{
135            data: &self.data,
136            u32_offset: offset
137        }
138    }
139}
140
141impl<'a> ToWasmMsgRef<'a> {
142
143    pub fn read_u32(&mut self) -> u32 {
144        let ret = if self.u32_offset & 1 != 0 {
145            (self.data[self.u32_offset >> 1] >> 32) as u32
146        }
147        else {
148            (self.data[self.u32_offset >> 1] & 0xffff_ffff) as u32
149        };
150        self.u32_offset += 1;
151        ret
152    }
153    
154    pub fn read_block_skip(&mut self)->ToWasmBlockSkip{
155        ToWasmBlockSkip{
156            base: self.u32_offset >> 1,
157            len: self.read_u32() as usize, 
158        }
159    }
160    
161    pub fn block_skip(&mut self, block_skip:ToWasmBlockSkip){
162        self.u32_offset = (block_skip.base + block_skip.len - 1)<<1
163    }
164    
165    pub fn read_f32(&mut self) -> f32 {
166        f32::from_bits(self.read_u32())
167    }
168    
169    pub fn read_u64(&mut self) -> u64 {
170        self.u32_offset += self.u32_offset & 1;
171        let ret = self.data[self.u32_offset >> 1];
172        self.u32_offset += 2;
173        ret
174    }
175    
176    pub fn read_f64(&mut self) -> f64 {
177        f64::from_bits(self.read_u64())
178    }
179    
180    pub fn read_string(&mut self) -> String {
181        let chars = self.read_u32();
182        let mut out = String::new();
183        for _ in 0..chars {
184            out.push(char::from_u32(self.read_u32()).unwrap_or('?'));
185        }
186        out
187    }
188    
189    pub fn was_last_block(&mut self)->bool{
190        self.u32_offset += self.u32_offset & 1;
191        self.u32_offset>>1 >= self.data.len()
192    }
193}