tabulon 0.1.10

A high-performance, JIT-compiled expression evaluation engine using Cranelift
Documentation
// Re-exported metadata for functions collected via #[function]
#[derive(Clone, Copy)]
pub struct FnMeta {
    pub name: &'static str,
    pub arity: u8,
    pub addr: *const u8,
    pub mod_path: &'static str,
    pub uses_ctx: bool,
    pub ctx_type_id_fn: Option<fn() -> ::core::any::TypeId>,
}

// Safe because addr points to a 'static extern "C" function shim generated by the macro
unsafe impl Sync for FnMeta {}

inventory::collect!(FnMeta);

/// A trait to extract the context type from an engine instance.
pub trait HasCtx {
    type Ctx;
}

impl<Ctx> HasCtx for crate::engine::Tabula<Ctx> {
    type Ctx = Ctx;
}

#[macro_export]
macro_rules! register_functions {
    ($eng:expr, $($name:ident),+ $(,)?) => {{
        // Determine the engine's context TypeId at compile site
        #[allow(dead_code)]
        fn __tabulon_engine_ctx_type_id<E: $crate::HasCtx>(_: &E) -> ::core::any::TypeId
        where
            <E as $crate::HasCtx>::Ctx: 'static,
        {
            ::core::any::TypeId::of::<<E as $crate::HasCtx>::Ctx>()
        }
        let __eng_tid = __tabulon_engine_ctx_type_id(&$eng);

        let mut res: Result<(), $crate::JitError> = Ok(());
        let wanted: &[&str] = &[ $( stringify!($name) ),+ ];
        for meta in $crate::inventory::iter::<$crate::FnMeta> {
            if wanted.contains(&meta.name) {
                // Runtime type-check to prevent mismatched context registration
                if meta.uses_ctx {
                    if let Some(ctx_tid_fn) = meta.ctx_type_id_fn {
                        if (ctx_tid_fn)() != __eng_tid {
                            res = Err($crate::JitError::Internal(format!(
                                "context type mismatch when registering {}: engine Ctx does not match function's Ctx",
                                meta.name
                            )));
                            break;
                        }
                    }
                }
                res = res.and_then(|_| unsafe {
                    match meta.arity {
                        0 => $eng.register_nullary(meta.name, std::mem::transmute::<*const u8, $crate::Fn0>(meta.addr), meta.uses_ctx),
                        1 => $eng.register_unary(meta.name, std::mem::transmute::<*const u8, $crate::Fn1>(meta.addr), meta.uses_ctx),
                        2 => $eng.register_binary(meta.name, std::mem::transmute::<*const u8, $crate::Fn2>(meta.addr), meta.uses_ctx),
                        3 => $eng.register_ternary(meta.name, std::mem::transmute::<*const u8, $crate::Fn3>(meta.addr), meta.uses_ctx),
                        _ => Err($crate::JitError::Internal(format!("unsupported arity {} for {}", meta.arity, meta.name))),
                    }
                });
            }
        }
        res
    }};
}

#[macro_export]
macro_rules! register_functions_typed {
    ($eng:expr, $($marker:path),+ $(,)?) => {{
        let mut res: Result<(), $crate::JitError> = Ok(());
        $(
            res = res.and_then(|_| $eng.register_typed::<$marker>());
        )+
        res
    }};
}

/// Type-equality helper for compile-time context matching (EngineCtx == FunctionCtx).
pub trait SameAs<T> {}
impl<T> SameAs<T> for T {}

/// Function metadata bound to an engine context type. Implemented by #[function]-generated markers.
pub trait FunctionForEngineCtx<EngineCtx> {
    const NAME: &'static str;
    const ARITY: u8;
    const USES_CTX: bool;
    fn addr() -> *const u8;
}

/// Resolver metadata bound to an engine context type. Implemented by #[resolver]-generated markers.
pub trait ResolverForEngineCtx<EngineCtx> {
    /// Symbol name to register with the JIT for this resolver.
    const NAME: &'static str;
    /// Address of the generated extern "C" shim: fn(ctx: *mut c_void, idx: u32) -> f64
    fn addr() -> *const u8;
}

#[macro_export]
macro_rules! register_resolver_typed {
    ($eng:expr, $marker:path) => {{
        $eng.set_var_getter_typed::<$marker>()
    }};
}