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}