cmajor 0.7.0

Rust bindings for the Cmajor JIT engine.
Documentation
use {
    crate::ffi::string::{CmajorString, CmajorStringPtr},
    std::{
        ffi::{c_char, c_int, CStr},
        ptr::null,
    },
};

#[repr(C)]
struct SyntaxTreeOptions {
    namespace_or_module: *const c_char,
    include_source_locations: bool,
    include_comments: bool,
    include_function_contents: bool,
}

#[repr(C)]
struct ProgramVTable {
    add_ref: unsafe extern "system" fn(*mut Program) -> c_int,
    release: unsafe extern "system" fn(*mut Program) -> c_int,
    ref_count: unsafe extern "system" fn(*const Program) -> c_int,
    parse: unsafe extern "system" fn(
        *mut Program,
        *const c_char,
        *const c_char,
        isize,
    ) -> *mut CmajorString,
    get_syntax_tree:
        unsafe extern "system" fn(*mut Program, *const SyntaxTreeOptions) -> *mut CmajorString,
}

#[repr(C)]
pub struct Program {
    vtable: *const ProgramVTable,
}

#[derive(Debug)]
pub struct ProgramPtr {
    program: *mut Program,
}

impl ProgramPtr {
    pub unsafe fn new(program: *mut Program) -> Self {
        Self { program }
    }

    pub fn get(&self) -> *mut Program {
        self.program
    }

    pub fn parse(
        &self,
        file_name: Option<&CStr>,
        file_content: impl AsRef<str>,
    ) -> Result<(), CmajorStringPtr> {
        let file_name = file_name.map(CStr::as_ptr).unwrap_or(null());

        let file_content_len = file_content.as_ref().len() as isize;
        let file_content = file_content.as_ref().as_ptr().cast();

        let error = unsafe {
            ((*(*self.program).vtable).parse)(
                self.program,
                file_name,
                file_content,
                file_content_len,
            )
        };

        if error.is_null() {
            return Ok(());
        }

        Err(unsafe { CmajorStringPtr::new(error) })
    }
}

impl Drop for ProgramPtr {
    fn drop(&mut self) {
        unsafe { ((*(*self.program).vtable).release)(self.program) };
    }
}