co3 0.4.0

Build C API from Rust
Documentation
use co3::{ReprC, ffi, rust_spec::RustSpec};
type CCallback = extern "C" fn(Value, Value) -> Value;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RustSpec, ReprC)]
#[reprC(identity)]
#[repr(C)]
struct Value(u8);

extern "C" fn sum_pair(left: Value, right: Value) -> Value {
    Value(left.0 + right.0)
}

fn apply_callback(callback: CCallback, left: Value, right: Value) -> Value {
    callback(left, right)
}

fn apply_optional_callback(callback: Option<CCallback>, value: Value) -> Value {
    callback.map_or(value, |call| call(value, Value(1)))
}

ffi! {
    #![unsafe(export("C"))]
    #![symbol_prefix = "abi_c_callback"]

    fn apply_callback(callback: CCallback, left: Value, right: Value) -> Value;
    fn apply_optional_callback(callback: Option<CCallback>, value: Value) -> Value;
}

mod imported {
    use co3::ffi;

    use super::*;

    ffi! {
        #![unsafe(extern("C"))]
        #![symbol_prefix = "abi_c_callback"]

        pub fn apply_callback(callback: super::CCallback, left: Value, right: Value) -> Value;
        pub fn apply_optional_callback(callback: Option<super::CCallback>, value: Value) -> Value;
    }
}

#[test]
fn c_callback_crosses_export_and_import() {
    assert_eq!(
        imported::apply_callback(sum_pair, Value(19), Value(23)),
        Value(42)
    );
    assert_eq!(
        imported::apply_optional_callback(Some(sum_pair), Value(41)),
        Value(42)
    );
    assert_eq!(
        imported::apply_optional_callback(None, Value(41)),
        Value(41)
    );
}