fraiseql_functions/runtime/mod.rs
1//! Function runtime trait and implementations.
2
3#[cfg(feature = "runtime-wasm")]
4pub mod wasm;
5
6#[cfg(feature = "runtime-deno")]
7pub mod deno;
8
9#[cfg(all(test, feature = "runtime-wasm", feature = "runtime-deno"))]
10mod parity_tests;
11
12use std::future::Future;
13
14use async_trait::async_trait;
15use fraiseql_error::Result;
16
17use crate::{
18 HostContext,
19 types::{EventPayload, FunctionModule, FunctionResult, ResourceLimits},
20};
21
22/// Trait for function execution backends (WASM, Deno, etc.).
23///
24/// Implementors provide the ability to load and execute function modules
25/// with resource limits enforced. This trait uses native async for zero-cost
26/// abstraction on hot paths.
27pub trait FunctionRuntime: Send + Sync {
28 /// Execute a function module with the given event and host context.
29 ///
30 /// # Errors
31 ///
32 /// Returns `Err` if:
33 /// - The module cannot be loaded or parsed
34 /// - Execution raises an error (runtime error, timeout, memory limit exceeded)
35 /// - The host context raises an error
36 fn invoke<H>(
37 &self,
38 module: &FunctionModule,
39 event: EventPayload,
40 host: &H,
41 limits: ResourceLimits,
42 ) -> impl Future<Output = Result<FunctionResult>> + Send
43 where
44 H: HostContext + ?Sized;
45
46 /// Get the list of file extensions this runtime supports.
47 fn supported_extensions(&self) -> &[&str];
48
49 /// Check if this runtime supports hot-reloading modules without restart.
50 fn supports_hot_reload(&self) -> bool;
51
52 /// Get the name of this runtime (e.g., "wasm", "deno").
53 fn name(&self) -> &str;
54}
55
56/// Type alias for a boxable function runtime (with static lifetime bounds).
57/// Used for dynamic dispatch where concrete types aren't known at compile time.
58pub type BoxedFunctionRuntime = Box<dyn FunctionRuntime + Send + Sync>;
59
60/// Object-safe variant of `FunctionRuntime` for dynamic dispatch.
61///
62/// This trait has the same semantic methods but without generic parameters,
63/// making it suitable for `Arc<dyn SendFunctionRuntime>`. The `invoke_raw`
64/// method uses a [`NoopHostContext`](crate::NoopHostContext) internally.
65#[async_trait]
66pub trait SendFunctionRuntime: Send + Sync {
67 /// Execute a function module with the given event and resource limits.
68 ///
69 /// Uses [`NoopHostContext`](crate::NoopHostContext) — callers that need
70 /// host-bridge functionality should use [`FunctionRuntime::invoke`] with
71 /// a concrete host context instead.
72 ///
73 /// # Errors
74 ///
75 /// Returns `Err` if the module cannot be loaded, or execution fails.
76 async fn invoke_raw(
77 &self,
78 module: &FunctionModule,
79 event: EventPayload,
80 limits: ResourceLimits,
81 ) -> Result<FunctionResult>;
82
83 /// Get the list of file extensions this runtime supports.
84 fn supported_extensions(&self) -> &[&str];
85
86 /// Check if this runtime supports hot-reloading modules without restart.
87 fn supports_hot_reload(&self) -> bool;
88
89 /// Get the name of this runtime (e.g., "wasm", "deno").
90 fn name(&self) -> &str;
91}