cardinal_wasm_plugins/
runner.rs1use crate::instance::WasmInstance;
2use crate::plugin::WasmPlugin;
3use crate::ExecutionContext;
4use cardinal_errors::internal::CardinalInternalError;
5use cardinal_errors::CardinalError;
6use std::collections::HashMap;
7use std::sync::Arc;
8use wasmer::TypedFunction;
9use wasmer::{Function, FunctionEnv, Store};
10
11#[derive(Debug)]
12pub struct ExecutionResult {
13 pub should_continue: bool,
14 pub execution_context: ExecutionContext,
15}
16
17pub type HostFunctionBuilder =
18 Arc<dyn Fn(&mut Store, &FunctionEnv<ExecutionContext>) -> Function + Send + Sync>;
19pub type HostFunctionMap = HashMap<String, Vec<(String, HostFunctionBuilder)>>;
20
21pub struct WasmRunner<'a> {
22 pub plugin: &'a WasmPlugin,
23 host_imports: Option<&'a HostFunctionMap>,
24}
25
26impl<'a> WasmRunner<'a> {
27 pub fn new(plugin: &'a WasmPlugin, host_imports: Option<&'a HostFunctionMap>) -> Self {
28 Self {
29 plugin,
30 host_imports,
31 }
32 }
33
34 pub fn run(&self, exec_ctx: ExecutionContext) -> Result<ExecutionResult, CardinalError> {
35 let mut instance = WasmInstance::from_plugin(self.plugin, self.host_imports)?;
37
38 {
39 let ctx = instance.env.as_mut(&mut instance.store);
40 let memory = ctx.memory().clone();
41 *ctx = exec_ctx;
42 *ctx.memory_mut() = memory;
43 }
44
45 let handle: TypedFunction<(i32, i32), i32> = instance
47 .instance
48 .exports
49 .get_typed_function(&instance.store, "handle")
50 .map_err(|e| {
51 CardinalError::InternalError(CardinalInternalError::InvalidWasmModule(format!(
52 "missing `handle` export {e}"
53 )))
54 })?;
55
56 let alloc: TypedFunction<(i32, i32), i32> = instance
57 .instance
58 .exports
59 .get_typed_function(&instance.store, "__new")
60 .map_err(|e| {
61 CardinalError::InternalError(CardinalInternalError::InvalidWasmModule(format!(
62 "missing `alloc` export {e}"
63 )))
64 })?;
65
66 let body_opt = {
67 let ctx_ref = instance.env.as_ref(&instance.store);
68 ctx_ref.body().clone()
69 };
70
71 let (ptr, len) = if let Some(body) = body_opt.filter(|b| !b.is_empty()) {
72 let len = body.len() as i32;
73
74 let p = alloc.call(&mut instance.store, len, 0).map_err(|e| {
75 CardinalError::InternalError(CardinalInternalError::InvalidWasmModule(format!(
76 "Alloc failed {e}"
77 )))
78 })?;
79
80 {
81 let view = instance.memory.view(&instance.store);
82 view.write(p as u64, &body).map_err(|e| {
83 CardinalError::InternalError(CardinalInternalError::InvalidWasmModule(format!(
84 "Writing Body failed {e}"
85 )))
86 })?;
87 }
88
89 (p, len)
90 } else {
91 (0, 0)
92 };
93
94 let decision = handle.call(&mut instance.store, ptr, len).map_err(|e| {
95 CardinalError::InternalError(CardinalInternalError::InvalidWasmModule(format!(
96 "WASM Handle call failed {e}"
97 )))
98 })?;
99
100 Ok(ExecutionResult {
101 should_continue: decision == 1,
102 execution_context: instance.env.as_ref(&instance.store).clone(),
103 })
104 }
105}