cmajor 0.7.0

Rust bindings for the Cmajor JIT engine.
Documentation
use {
    crate::value::types::Primitive,
    std::{any::Any, cell::RefCell, ffi::c_void, panic::UnwindSafe, ptr::null_mut},
};

pub fn get_external_function(name: &str, signature: &[Primitive]) -> *mut c_void {
    match (name, signature) {
        ("rust::test::assert", &[Primitive::Bool]) => rust_assert as *mut c_void,
        ("rust::test::assertEqual", &[Primitive::Int32, Primitive::Int32]) => {
            rust_assert_eq_i32 as *mut c_void
        }
        ("rust::test::assertEqual", &[Primitive::Int64, Primitive::Int64]) => {
            rust_assert_eq_i64 as *mut c_void
        }
        ("rust::test::assertEqual", &[Primitive::Float32, Primitive::Float32]) => {
            rust_assert_eq_f32 as *mut c_void
        }
        ("rust::test::assertEqual", &[Primitive::Float64, Primitive::Float64]) => {
            rust_assert_eq_f64 as *mut c_void
        }
        ("rust::debug::print", &[Primitive::Bool]) => rust_print_bool as *mut c_void,
        ("rust::debug::print", &[Primitive::Int32]) => rust_print_i32 as *mut c_void,
        ("rust::debug::print", &[Primitive::Int64]) => rust_print_i64 as *mut c_void,
        ("rust::debug::print", &[Primitive::Float32]) => rust_print_f32 as *mut c_void,
        ("rust::debug::print", &[Primitive::Float64]) => rust_print_f64 as *mut c_void,
        _ => null_mut(),
    }
}

pub fn check_for_panic() {
    PANIC.with(|panic| {
        if let Some(err) = panic.borrow_mut().take() {
            std::panic::resume_unwind(err);
        }
    });
}

thread_local! {
    static PANIC: RefCell<Option<Box<dyn Any + Send>>> = RefCell::new(None);
}

fn catch_unwind_and_store_panic<F: FnOnce() -> R + UnwindSafe, R>(f: F) {
    let panic = std::panic::catch_unwind(f);

    if let Err(err) = panic {
        PANIC.with(|panic| {
            if panic.borrow().is_none() {
                panic.replace(Some(err));
            }
        });
    }
}

extern "C" fn rust_assert(condition: bool) {
    catch_unwind_and_store_panic(|| {
        assert!(condition, "cmajor assertion failed");
    });
}

macro_rules! make_assert_eq_fn {
    ($name:ident, $t:ty) => {
        extern "C" fn $name(a: $t, b: $t) {
            catch_unwind_and_store_panic(|| {
                assert_eq!(a, b, "cmajor assertion failed");
            });
        }
    };
}

make_assert_eq_fn!(rust_assert_eq_i32, i32);
make_assert_eq_fn!(rust_assert_eq_i64, i64);
make_assert_eq_fn!(rust_assert_eq_f32, f32);
make_assert_eq_fn!(rust_assert_eq_f64, f64);

macro_rules! make_print_fn {
    ($name:ident, $t:ty) => {
        extern "C" fn $name(value: $t) {
            catch_unwind_and_store_panic(|| {
                println!("{}", value);
            });
        }
    };
}

make_print_fn!(rust_print_bool, bool);
make_print_fn!(rust_print_i32, i32);
make_print_fn!(rust_print_i64, i64);
make_print_fn!(rust_print_f32, f32);
make_print_fn!(rust_print_f64, f64);