macro_rules! custom {
    ($name:ident $(<$($t:tt),*>)? $({$($k:ident : $v:expr),* $(,)? })?) => { ... };
    {name : $name:expr $(, fixed_length: $fl:expr)? $(, $($k:ident : $v:expr),*)? $(,)? } => { ... };
}
Expand description

Create a custom OCaml type from an existing Rust type

See the struct custom_operations section in the OCaml manual for more information about each field

struct MyType {
    s: String,
    i: i32,
}

unsafe extern "C" fn mytype_compare(a: ocaml::Raw, b: ocaml::Raw) -> i32 {
    let a = a.as_pointer::<MyType>();
    let b = b.as_pointer::<MyType>();

    let a_i = a.as_ref().i;
    let b_i = b.as_ref().i;

    if a_i == b_i {
        return 0
    }

    if a_i < b_i {
        return -1;
    }

    1
}

ocaml::custom!(MyType {
    compare: mytype_compare,
});

// This is equivalent to
struct MyType2 {
    s: String,
    i: i32,
}


// This is the default finalizer
unsafe extern "C" fn mytype2_finalizer(v: ocaml::Raw) {
    let ptr = v.as_pointer::<MyType2>();
    ptr.drop_in_place();
}

impl ocaml::Custom for MyType2 {
    const NAME: &'static str = "rust.MyType\0";

    const OPS: ocaml::custom::CustomOps = ocaml::custom::CustomOps {
        identifier: Self::NAME.as_ptr() as *mut ocaml::sys::Char,
        finalize: Some(mytype2_finalizer),
        compare: Some(mytype_compare),
        .. ocaml::custom::DEFAULT_CUSTOM_OPS
    };
}

Additionally, custom can be used inside the impl block:

extern "C" fn implexample_finalizer(_: ocaml::Raw) {
    println!("This runs when the value gets garbage collected");
}

struct ImplExample<'a>(&'a str);

impl<'a> ocaml::Custom for ImplExample<'a> {
    ocaml::custom! {
        name: "rust.ImplExample",
        finalize: implexample_finalizer
    }
}

// This is equivalent to:

struct ImplExample2<'a>(&'a str);

ocaml::custom!(ImplExample2<'a> {
    finalize: implexample_finalizer,
});