venus_core/execute/
ffi.rs

1//! FFI type definitions for cell execution.
2//!
3//! This module defines the function pointer types used to call
4//! compiled cell entry points, and the result codes they return.
5
6/// Result code from cell execution.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8#[repr(i32)]
9pub enum ExecutionResult {
10    /// Cell executed successfully
11    Success = 0,
12    /// Failed to deserialize input
13    DeserializationError = -1,
14    /// Cell function returned an error
15    CellError = -2,
16    /// Failed to serialize output
17    SerializationError = -3,
18    /// Cell panicked during execution
19    Panic = -4,
20}
21
22impl From<i32> for ExecutionResult {
23    fn from(code: i32) -> Self {
24        match code {
25            0 => Self::Success,
26            -1 => Self::DeserializationError,
27            -2 => Self::CellError,
28            -3 => Self::SerializationError,
29            -4 => Self::Panic,
30            _ => Self::CellError, // Unknown codes treated as cell errors
31        }
32    }
33}
34
35// =============================================================================
36// FFI Entry Function Types
37// =============================================================================
38//
39// Type aliases for FFI entry functions with N inputs.
40// Each input requires (ptr, len) pairs, followed by widget_values (ptr, len),
41// then output params (out_ptr, out_len).
42// All functions return i32 status code and write output to (out_ptr, out_len).
43
44/// Entry function for cells with 0 dependencies.
45pub type EntryFn0 = unsafe extern "C" fn(
46    *const u8, usize,  // widget_values
47    *mut *mut u8, *mut usize,
48) -> i32;
49
50/// Entry function for cells with 1 dependency.
51pub type EntryFn1 = unsafe extern "C" fn(
52    *const u8, usize,  // dep 0
53    *const u8, usize,  // widget_values
54    *mut *mut u8, *mut usize,
55) -> i32;
56
57/// Entry function for cells with 2 dependencies.
58pub type EntryFn2 = unsafe extern "C" fn(
59    *const u8, usize,  // dep 0
60    *const u8, usize,  // dep 1
61    *const u8, usize,  // widget_values
62    *mut *mut u8, *mut usize,
63) -> i32;
64
65/// Entry function for cells with 3 dependencies.
66pub type EntryFn3 = unsafe extern "C" fn(
67    *const u8, usize,  // dep 0
68    *const u8, usize,  // dep 1
69    *const u8, usize,  // dep 2
70    *const u8, usize,  // widget_values
71    *mut *mut u8, *mut usize,
72) -> i32;
73
74/// Entry function for cells with 4 dependencies.
75pub type EntryFn4 = unsafe extern "C" fn(
76    *const u8, usize,  // dep 0
77    *const u8, usize,  // dep 1
78    *const u8, usize,  // dep 2
79    *const u8, usize,  // dep 3
80    *const u8, usize,  // widget_values
81    *mut *mut u8, *mut usize,
82) -> i32;
83
84/// Entry function for cells with 5 dependencies.
85pub type EntryFn5 = unsafe extern "C" fn(
86    *const u8, usize,  // dep 0
87    *const u8, usize,  // dep 1
88    *const u8, usize,  // dep 2
89    *const u8, usize,  // dep 3
90    *const u8, usize,  // dep 4
91    *const u8, usize,  // widget_values
92    *mut *mut u8, *mut usize,
93) -> i32;
94
95/// Entry function for cells with 6 dependencies.
96pub type EntryFn6 = unsafe extern "C" fn(
97    *const u8, usize,  // dep 0
98    *const u8, usize,  // dep 1
99    *const u8, usize,  // dep 2
100    *const u8, usize,  // dep 3
101    *const u8, usize,  // dep 4
102    *const u8, usize,  // dep 5
103    *const u8, usize,  // widget_values
104    *mut *mut u8, *mut usize,
105) -> i32;
106
107/// Entry function for cells with 7 dependencies.
108pub type EntryFn7 = unsafe extern "C" fn(
109    *const u8, usize,  // dep 0
110    *const u8, usize,  // dep 1
111    *const u8, usize,  // dep 2
112    *const u8, usize,  // dep 3
113    *const u8, usize,  // dep 4
114    *const u8, usize,  // dep 5
115    *const u8, usize,  // dep 6
116    *const u8, usize,  // widget_values
117    *mut *mut u8, *mut usize,
118) -> i32;
119
120/// Entry function for cells with 8 dependencies.
121pub type EntryFn8 = unsafe extern "C" fn(
122    *const u8, usize,  // dep 0
123    *const u8, usize,  // dep 1
124    *const u8, usize,  // dep 2
125    *const u8, usize,  // dep 3
126    *const u8, usize,  // dep 4
127    *const u8, usize,  // dep 5
128    *const u8, usize,  // dep 6
129    *const u8, usize,  // dep 7
130    *const u8, usize,  // widget_values
131    *mut *mut u8, *mut usize,
132) -> i32;
133
134// =============================================================================
135// FFI Dispatch Macro
136// =============================================================================
137
138/// Macro to generate FFI dispatch for cells with N dependencies.
139///
140/// This eliminates duplication across individual call functions.
141/// Each invocation generates a typed FFI call with the appropriate entry function type.
142///
143/// # Safety
144/// The generated code trusts that the symbol has the correct signature.
145///
146/// # Usage
147/// ```ignore
148/// call_cell_n_deps!(self, loaded, symbol_name, inputs, widget_values, EntryFn2, 0, 1)
149/// ```
150macro_rules! call_cell_n_deps {
151    ($executor:expr, $loaded:expr, $symbol_name:expr, $inputs:expr, $widget_values:expr, $fn_type:ty, $($idx:tt),*) => {{
152        use libloading::Symbol;
153        use $crate::error::Error;
154
155        let func: Symbol<$fn_type> = unsafe {
156            $loaded.library.get($symbol_name.as_bytes())
157        }.map_err(|e| {
158            Error::Execution(format!("Failed to get symbol {}: {}", $symbol_name, e))
159        })?;
160
161        let mut out_ptr: *mut u8 = std::ptr::null_mut();
162        let mut out_len: usize = 0;
163
164        // Extract input byte slices
165        $( let _input_bytes = $inputs[$idx].bytes(); )*
166        let inputs_array = [$( $inputs[$idx].bytes() ),*];
167
168        // Call the FFI function with widget_values
169        let result_code = unsafe {
170            func(
171                $( inputs_array[$idx].as_ptr(), inputs_array[$idx].len(), )*
172                $widget_values.as_ptr(), $widget_values.len(),
173                &mut out_ptr,
174                &mut out_len,
175            )
176        };
177
178        $executor.process_ffi_result(result_code, out_ptr, out_len, &$loaded.compiled.name)
179    }};
180}
181
182pub(crate) use call_cell_n_deps;
183
184#[cfg(test)]
185mod tests {
186    use super::*;
187
188    #[test]
189    fn test_execution_result_from_i32() {
190        assert_eq!(ExecutionResult::from(0), ExecutionResult::Success);
191        assert_eq!(
192            ExecutionResult::from(-1),
193            ExecutionResult::DeserializationError
194        );
195        assert_eq!(ExecutionResult::from(-2), ExecutionResult::CellError);
196        assert_eq!(
197            ExecutionResult::from(-3),
198            ExecutionResult::SerializationError
199        );
200        assert_eq!(ExecutionResult::from(-4), ExecutionResult::Panic);
201        assert_eq!(ExecutionResult::from(-99), ExecutionResult::CellError);
202    }
203}