vertigo_cli/serve/wasm/
data_context.rs

1use vertigo::{JsValue, MemoryBlock};
2use wasmtime::{AsContextMut, Caller, Extern, Instance, Memory, Store, StoreContextMut};
3
4use crate::serve::request_state::RequestState;
5
6pub enum DataContext<'a> {
7    Caller {
8        caller: Caller<'a, RequestState>,
9    },
10    Store {
11        store: &'a mut Store<RequestState>,
12        instance: Instance,
13    },
14}
15
16impl<'a> DataContext<'a> {
17    pub fn from_caller(caller: Caller<'a, RequestState>) -> Self {
18        DataContext::Caller { caller }
19    }
20
21    pub fn from_store(store: &'a mut Store<RequestState>, instance: Instance) -> Self {
22        DataContext::Store { store, instance }
23    }
24
25    fn get_context(&mut self) -> StoreContextMut<'_, RequestState> {
26        match self {
27            Self::Caller { caller } => caller.as_context_mut(),
28            Self::Store { store, .. } => store.as_context_mut(),
29        }
30    }
31    fn get_memory(&mut self) -> Memory {
32        match self {
33            Self::Caller { caller } => {
34                let Some(Extern::Memory(memory)) = caller.get_export("memory") else {
35                    unreachable!("get_memory failed (caller)")
36                };
37
38                memory
39            }
40            Self::Store { instance, store } => {
41                let context = store.as_context_mut();
42                let Some(Extern::Memory(memory)) = instance.get_export(context, "memory") else {
43                    unreachable!("get_memory failed (store)")
44                };
45
46                memory
47            }
48        }
49    }
50
51    pub fn get_value(&mut self, ptr: u32, offset: u32) -> JsValue {
52        let memory = self.get_memory();
53        let context = self.get_context();
54
55        let buff = memory.data(&context);
56
57        let ptr = ptr as usize;
58        let offset = offset as usize;
59
60        let slice = &buff[ptr..(ptr + offset)];
61
62        let block = MemoryBlock::from_slice(slice);
63        match JsValue::from_block(block) {
64            Ok(value) => value,
65            Err(error) => {
66                log::info!("JsValue decoding problem, error={error}");
67                JsValue::Undefined
68            }
69        }
70    }
71
72    pub fn get_string_from(&mut self, ptr: u32, offset: u32) -> Option<String> {
73        let memory = self.get_memory();
74        let context = self.get_context();
75        let buff = memory.data(&context);
76
77        let ptr = ptr as usize;
78        let offset = offset as usize;
79
80        let slice = &buff[ptr..(ptr + offset)];
81
82        let slice_vec = Vec::from(slice);
83
84        let Ok(result) = String::from_utf8(slice_vec) else {
85            log::error!("panic message decoding problem");
86            return None;
87        };
88
89        Some(result)
90    }
91
92    fn alloc(&mut self, size: usize) -> usize {
93        let alloc_inner = match self {
94            Self::Caller { caller, .. } => {
95                let Some(Extern::Func(alloc_inner)) = caller.get_export("alloc") else {
96                    log::error!("Alloc failed (caller)");
97                    return 0;
98                };
99                alloc_inner
100            }
101            Self::Store {
102                store, instance, ..
103            } => {
104                let Some(Extern::Func(alloc_inner)) = instance.get_export(store, "alloc") else {
105                    log::error!("Alloc failed (store)");
106                    return 0;
107                };
108
109                alloc_inner
110            }
111        };
112
113        let mut context = self.get_context();
114        let Ok(alloc) = alloc_inner
115            .typed::<u32, u32>(&mut context)
116            .inspect_err(|err| log::error!("Alloc failed (2): {err}"))
117        else {
118            return 0;
119        };
120
121        alloc.call(&mut context, size as u32)
122            .inspect_err(|err| log::error!("Alloc failed (3): {err}"))
123            .unwrap_or(0) as usize
124    }
125
126    pub fn save_value(&mut self, value: JsValue) -> u32 {
127        if let JsValue::Undefined = value {
128            return 0;
129        }
130
131        let block = value.to_snapshot();
132        let block = block.convert_to_vec();
133        let size = block.len();
134
135        let ptr = self.alloc(size);
136
137        let memory = self.get_memory();
138        let context = self.get_context();
139        let buff = memory.data_mut(context);
140
141        buff[ptr..(ptr + size)].clone_from_slice(block.as_slice());
142
143        ptr as u32
144    }
145}