reifydb_engine/procedure/
wasm.rs1use postcard::to_stdvec;
7use reifydb_core::value::column::columns::Columns;
8use reifydb_sdk::{error::FFIError, marshal::wasm::unmarshal_columns_from_bytes};
9use reifydb_transaction::transaction::Transaction;
10use reifydb_type::Result;
11use reifydb_wasm::{Engine, SpawnBinary, module::value::Value, source};
12
13use super::{Procedure, context::ProcedureContext};
14
15pub struct WasmProcedure {
23 name: String,
24 wasm_bytes: Vec<u8>,
25}
26
27impl WasmProcedure {
28 pub fn new(name: impl Into<String>, wasm_bytes: Vec<u8>) -> Self {
29 Self {
30 name: name.into(),
31 wasm_bytes,
32 }
33 }
34
35 pub fn name(&self) -> &str {
36 &self.name
37 }
38}
39
40unsafe impl Send for WasmProcedure {}
43unsafe impl Sync for WasmProcedure {}
44
45impl Procedure for WasmProcedure {
46 fn call(&self, ctx: &ProcedureContext, _tx: &mut Transaction<'_>) -> Result<Columns> {
47 let params_bytes = to_stdvec(ctx.params).map_err(|e| {
48 FFIError::Other(format!("WASM procedure '{}' failed to serialize params: {}", self.name, e))
49 })?;
50
51 let mut engine = Engine::default();
52 engine.spawn(source::binary::bytes(&self.wasm_bytes)).map_err(|e| {
53 FFIError::Other(format!("WASM procedure '{}' failed to load: {:?}", self.name, e))
54 })?;
55
56 let alloc_result = engine.invoke("alloc", &[Value::I32(params_bytes.len() as i32)]).map_err(|e| {
58 FFIError::Other(format!("WASM procedure '{}' alloc failed: {:?}", self.name, e))
59 })?;
60
61 let params_ptr = match alloc_result.first() {
62 Some(Value::I32(v)) => *v,
63 _ => {
64 return Err(FFIError::Other(format!(
65 "WASM procedure '{}': alloc returned unexpected result",
66 self.name
67 ))
68 .into());
69 }
70 };
71
72 engine.write_memory(params_ptr as usize, ¶ms_bytes).map_err(|e| {
74 FFIError::Other(format!("WASM procedure '{}' write_memory failed: {:?}", self.name, e))
75 })?;
76
77 let result = engine
79 .invoke("procedure", &[Value::I32(params_ptr), Value::I32(params_bytes.len() as i32)])
80 .map_err(|e| {
81 FFIError::Other(format!(
82 "WASM procedure '{}' procedure call failed: {:?}",
83 self.name, e
84 ))
85 })?;
86
87 let output_ptr = match result.first() {
88 Some(Value::I32(v)) => *v as usize,
89 _ => {
90 return Err(FFIError::Other(format!(
91 "WASM procedure '{}': procedure returned unexpected result",
92 self.name
93 ))
94 .into());
95 }
96 };
97
98 let len_bytes = engine.read_memory(output_ptr, 4).map_err(|e| {
100 FFIError::Other(format!("WASM procedure '{}' read output length failed: {:?}", self.name, e))
101 })?;
102
103 let output_len = u32::from_le_bytes([len_bytes[0], len_bytes[1], len_bytes[2], len_bytes[3]]) as usize;
104
105 let output_bytes = engine.read_memory(output_ptr + 4, output_len).map_err(|e| {
107 FFIError::Other(format!("WASM procedure '{}' read output data failed: {:?}", self.name, e))
108 })?;
109
110 Ok(unmarshal_columns_from_bytes(&output_bytes))
111 }
112}