vertigo_cli/serve/wasm/
data_context.rs1use 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}