Skip to main content

flow_gate_ffi/
result.rs

1use std::ffi::CString;
2use std::os::raw::c_char;
3
4use flow_gate_core::FlowGateError;
5
6/// Opaque FFI error struct. The `message` field is a heap-allocated C string
7/// that must be freed by calling `flow_gate_ffi_error_free`.
8#[repr(C)]
9pub struct FfiError {
10    pub message: *mut c_char,
11    pub code: u32,
12}
13
14impl FfiError {
15    pub fn from_gating_error(err: &FlowGateError) -> Self {
16        let msg = CString::new(err.to_string()).unwrap_or_else(|_| unsafe {
17            // SAFETY: This literal contains no null bytes, so from_raw_unchecked is safe.
18            CString::from_vec_unchecked(b"unknown error".to_vec())
19        });
20        Self {
21            message: msg.into_raw(),
22            code: error_code(err),
23        }
24    }
25}
26
27/// Frees the message string inside an `FfiError`.
28///
29/// # Safety
30/// - `err` must be a valid, previously constructed `FfiError` whose `message`
31///   field was produced by `CString::into_raw()`.
32/// - This function must not be called more than once for the same `message`.
33#[no_mangle]
34pub unsafe extern "C" fn flow_gate_ffi_error_free(err: *mut FfiError) {
35    if err.is_null() {
36        return;
37    }
38    let err = &mut *err;
39    if !err.message.is_null() {
40        // SAFETY: message was created by CString::into_raw in FfiError::from_gating_error.
41        drop(CString::from_raw(err.message));
42        err.message = std::ptr::null_mut();
43    }
44}
45
46fn error_code(err: &FlowGateError) -> u32 {
47    match err {
48        FlowGateError::InvalidTransformParam(_) => 1,
49        FlowGateError::InvalidGate(_) => 2,
50        FlowGateError::UnknownParameter(_) => 3,
51        FlowGateError::XmlParse(_) => 4,
52        FlowGateError::NotPositiveDefinite => 5,
53        FlowGateError::CyclicGateReference(_) => 6,
54        FlowGateError::UnknownGateReference(_, _) => 7,
55        FlowGateError::MissingAttribute(_, _) => 8,
56        FlowGateError::InvalidFloat(_, _) => 9,
57        FlowGateError::BooleanNotArity(_, _) => 10,
58        FlowGateError::BooleanEmptyOperands(_) => 11,
59        FlowGateError::DimensionMismatch(_, _) => 12,
60        FlowGateError::MissingParentGate(_) => 13,
61    }
62}