Skip to main content

diplomat_runtime/
callback.rs

1#[cfg(feature = "jvm-callback-support")]
2use alloc::boxed::Box;
3use core::ffi::c_void;
4#[cfg(feature = "jvm-callback-support")]
5use jni::{
6    objects::{GlobalRef, JObject},
7    sys::jlong,
8    JNIEnv,
9};
10
11/// Struct representing a callback from Rust into a foreign language
12///
13/// This is largely used internally by the Diplomat macro, and should not need to be constructed
14/// manually outside of that context
15#[repr(C)]
16pub struct DiplomatCallback<ReturnType> {
17    /// Any data required to run the callback; e.g. a pointer to the
18    /// callback wrapper object in the foreign runtime + the runtime itself
19    pub data: *mut c_void,
20    /// Function to actually run the callback. Note the first param is mutable, but depending
21    /// on if this is passed to a Fn or FnMut may not actually need to be.
22    /// FFI-Callers of said functions should cast to mutable.
23    ///
24    /// Takes in `self.data` and any number of additional arguments.
25    pub run_callback: unsafe extern "C" fn(*mut c_void, ...) -> ReturnType,
26    /// Function to destroy this callback struct.
27    ///
28    /// Takes in `self.data`
29    pub destructor: Option<unsafe extern "C" fn(*mut c_void)>,
30}
31
32impl<ReturnType> Drop for DiplomatCallback<ReturnType> {
33    fn drop(&mut self) {
34        if let Some(destructor) = self.destructor {
35            unsafe {
36                (destructor)(self.data);
37            }
38        }
39    }
40}
41
42// return a pointer to a JNI GlobalRef, which is a JVM GC root to the object provided.
43// this can then be stored as a field in a struct, so that the struct
44// is not deallocated until the JVM calls a destructor that unwraps
45// the GlobalRef so it can be dropped.
46#[cfg(feature = "jvm-callback-support")]
47#[no_mangle]
48extern "system" fn create_rust_jvm_cookie<'local>(
49    env: JNIEnv<'local>,
50    obj_to_ref: JObject<'local>,
51) -> jlong {
52    let global_ref = env.new_global_ref(obj_to_ref).unwrap();
53    Box::into_raw(Box::new(global_ref)) as jlong
54}
55
56#[cfg(feature = "jvm-callback-support")]
57#[no_mangle]
58extern "system" fn destroy_rust_jvm_cookie(global_ref_boxed: jlong) {
59    unsafe {
60        drop(Box::from_raw(global_ref_boxed as *mut GlobalRef));
61    }
62}