cmajor 0.7.0

Rust bindings for the Cmajor JIT engine.
Documentation
use {
    crate::ffi::engine_factory::{EngineFactory, EngineFactoryPtr},
    program::Program,
    std::{
        ffi::{c_char, c_void, CStr},
        path::Path,
    },
};

mod engine;
mod engine_factory;
mod performer;
mod program;

mod externals;
mod string;
pub(crate) mod types;

pub use {engine::EnginePtr, performer::PerformerPtr, program::ProgramPtr};

pub struct Library {
    entry_points: *mut EntryPoints,
}

type CMajorGetEntryPointsV10 = unsafe extern "C" fn() -> *mut c_void;

#[cfg(feature = "static")]
extern "C" {
    fn cmajor_getEntryPointsStatic() -> *mut c_void;
}

impl Library {
    #[cfg(feature = "static")]
    pub fn new() -> Self {
        let entry_points = unsafe { cmajor_getEntryPointsStatic() }.cast();
        Self { entry_points }
    }

    pub fn load(path_to_library: impl AsRef<Path>) -> Result<Self, libloading::Error> {
        const LIBRARY_ENTRY_POINT: &[u8] = b"cmajor_getEntryPointsV10";

        let library = unsafe { libloading::Library::new(path_to_library.as_ref()) }?;
        let entry_point_fn: libloading::Symbol<CMajorGetEntryPointsV10> =
            unsafe { library.get(LIBRARY_ENTRY_POINT)? };

        let entry_points = unsafe { entry_point_fn() }.cast();

        Ok(Self { entry_points })
    }

    pub fn version(&self) -> &CStr {
        let vtable = unsafe { (*self.entry_points).vtable };
        let version = unsafe { ((*vtable).get_version)(self.entry_points) };
        unsafe { CStr::from_ptr(version) }
    }

    pub fn engine_types(&self) -> &CStr {
        let vtable = unsafe { (*self.entry_points).vtable };
        let engine_types = unsafe { ((*vtable).get_engine_types)(self.entry_points) };
        unsafe { CStr::from_ptr(engine_types) }
    }

    pub fn create_program(&self) -> ProgramPtr {
        unsafe {
            let vtable = (*self.entry_points).vtable;
            let program = ((*vtable).create_program)(self.entry_points);
            ProgramPtr::new(program)
        }
    }

    pub fn create_engine_factory(&self, engine_type: &CStr) -> Option<EngineFactoryPtr> {
        unsafe {
            let vtable = (*self.entry_points).vtable;
            let engine_factory =
                ((*vtable).create_engine_factory)(self.entry_points, engine_type.as_ptr());

            (!engine_factory.is_null()).then(|| EngineFactoryPtr::new(engine_factory))
        }
    }
}

#[repr(C)]
struct EntryPointsVTable {
    get_version: unsafe extern "system" fn(*mut EntryPoints) -> *const c_char,
    create_program: unsafe extern "system" fn(*mut EntryPoints) -> *mut Program,
    get_engine_types: unsafe extern "system" fn(*mut EntryPoints) -> *const c_char,
    create_engine_factory:
        unsafe extern "system" fn(*mut EntryPoints, *const c_char) -> *mut EngineFactory,
}

#[repr(C)]
struct EntryPoints {
    vtable: *const EntryPointsVTable,
}