kimchi_stubs/caml/caml_pointer.rs
1macro_rules! impl_caml_pointer {
2 ($name: ident => $typ: ty) => {
3 #[derive(core::fmt::Debug, Clone, ::ocaml_gen::CustomType)]
4 pub struct $name(pub ::std::rc::Rc<std::cell::UnsafeCell<$typ>>);
5
6 impl $name {
7 extern "C" fn caml_pointer_finalize(v: ocaml::Raw) {
8 unsafe {
9 let v: ocaml::Pointer<$name> = v.as_pointer();
10 v.drop_in_place();
11 }
12 }
13
14 extern "C" fn caml_pointer_compare(_: ocaml::Raw, _: ocaml::Raw) -> i32 {
15 // Always return equal. We can use this for sanity checks, and
16 // anything else using this would be broken anyway.
17 0
18 }
19 }
20
21 ocaml::custom!($name {
22 finalize: $name::caml_pointer_finalize,
23 compare: $name::caml_pointer_compare,
24 });
25
26 unsafe impl<'a> ocaml::FromValue<'a> for $name {
27 fn from_value(x: ocaml::Value) -> Self {
28 let x = ocaml::Pointer::<Self>::from_value(x);
29 $name(x.as_ref().0.clone())
30 }
31 }
32
33 impl $name {
34 pub fn create(x: $typ) -> $name {
35 $name(::std::rc::Rc::new(std::cell::UnsafeCell::new(x)))
36 }
37 }
38
39 impl ::core::ops::Deref for $name {
40 type Target = $typ;
41
42 fn deref(&self) -> &Self::Target {
43 unsafe { &*self.0.get() }
44 }
45 }
46
47 impl ::core::ops::DerefMut for $name {
48 fn deref_mut(&mut self) -> &mut Self::Target {
49 unsafe {
50 // Wholely unsafe, Batman!
51 // We would use [`get_mut_unchecked`] here, but it is nightly-only.
52 // Instead, we get coerce our constant pointer to a mutable
53 // pointer, in the knowledge that
54 // * all of our mutations called from OCaml are blocking, so
55 // we won't have multiple live mutable references live
56 // simultaneously, and
57 // * the underlying pointer is in the correct state to be
58 // mutable, since we can call [`get_mut_unchecked`] in
59 // nightly, or can call [`get_mut`] and unwrap if this is
60 // the only live reference.
61 &mut *self.0.get()
62 }
63 }
64 }
65 };
66}