reifydb_extension/function/
wasm.rs1use reifydb_core::value::column::{Column, columns::Columns, data::ColumnData};
7use reifydb_routine::function::{Function, FunctionCapability, FunctionContext, FunctionInfo, error::FunctionError};
8use reifydb_sdk::marshal::wasm::{marshal_columns_to_bytes, unmarshal_columns_from_bytes};
9use reifydb_type::{fragment::Fragment, value::r#type::Type};
10
11use crate::loader::wasm::invoke_wasm_module;
12
13pub struct WasmScalarFunction {
25 info: FunctionInfo,
26 wasm_bytes: Vec<u8>,
27}
28
29impl WasmScalarFunction {
30 pub fn new(name: impl Into<String>, wasm_bytes: Vec<u8>) -> Self {
31 let name = name.into();
32 Self {
33 info: FunctionInfo::new(&name),
34 wasm_bytes,
35 }
36 }
37
38 pub fn name(&self) -> &str {
39 &self.info.name
40 }
41
42 fn err(&self, reason: impl Into<String>) -> FunctionError {
43 FunctionError::ExecutionFailed {
44 function: Fragment::internal(&self.info.name),
45 reason: reason.into(),
46 }
47 }
48}
49
50unsafe impl Send for WasmScalarFunction {}
53unsafe impl Sync for WasmScalarFunction {}
54
55impl Function for WasmScalarFunction {
56 fn info(&self) -> &FunctionInfo {
57 &self.info
58 }
59
60 fn capabilities(&self) -> &[FunctionCapability] {
61 &[FunctionCapability::Scalar]
62 }
63
64 fn return_type(&self, _input_types: &[Type]) -> Type {
65 Type::Any
66 }
67
68 fn execute(&self, ctx: &FunctionContext, args: &Columns) -> Result<Columns, FunctionError> {
69 let input_bytes = marshal_columns_to_bytes(args);
70 let label = format!("WASM scalar function '{}'", self.info.name);
71
72 let output_bytes = invoke_wasm_module(&self.wasm_bytes, "scalar", &input_bytes, &label)
73 .map_err(|e| self.err(e.to_string()))?;
74
75 let output_columns = unmarshal_columns_from_bytes(&output_bytes);
77
78 match output_columns.first() {
79 Some(col) => {
80 let data = col.data().clone();
81 Ok(Columns::new(vec![Column::new(ctx.fragment.clone(), data)]))
82 }
83 None => {
84 let data = ColumnData::none_typed(Type::Any, args.row_count());
85 Ok(Columns::new(vec![Column::new(ctx.fragment.clone(), data)]))
86 }
87 }
88 }
89}