1 #[cfg(feature = "jvm-callback-support")]
2 use alloc::boxed::Box;
3 use core::ffi::c_void;
4 #[cfg(feature = "jvm-callback-support")]
5 use jni::{
6 objects::{GlobalRef, JObject},
7 sys::jlong,
8 JNIEnv,
9 };
10
11 // struct representing a callback from Rust into a foreign language
12 // TODO restrict the return type?
13 #[repr(C)]
14 pub struct DiplomatCallback<ReturnType> {
15 // any data required to run the callback; e.g. a pointer to the
16 // callback wrapper object in the foreign runtime + the runtime itself
17 pub data: *mut c_void,
18 // function to actually run the callback
19 pub run_callback: unsafe extern "C" fn(*const c_void, ...) -> ReturnType,
20 // function to destroy this callback struct
21 pub destructor: Option<unsafe extern "C" fn(*const c_void)>,
22 }
23
24 impl<ReturnType> Drop for DiplomatCallback<ReturnType> {
drop(&mut self)25 fn drop(&mut self) {
26 if let Some(destructor) = self.destructor {
27 unsafe {
28 (destructor)(self.data);
29 }
30 }
31 }
32 }
33
34 // return a pointer to a JNI GlobalRef, which is a JVM GC root to the object provided.
35 // this can then be stored as a field in a struct, so that the struct
36 // is not deallocated until the JVM calls a destructor that unwraps
37 // the GlobalRef so it can be dropped.
38 #[cfg(feature = "jvm-callback-support")]
39 #[no_mangle]
create_rust_jvm_cookie<'local>( env: JNIEnv<'local>, obj_to_ref: JObject<'local>, ) -> jlong40 extern "system" fn create_rust_jvm_cookie<'local>(
41 env: JNIEnv<'local>,
42 obj_to_ref: JObject<'local>,
43 ) -> jlong {
44 let global_ref = env.new_global_ref(obj_to_ref).unwrap();
45 Box::into_raw(Box::new(global_ref)) as jlong
46 }
47
48 #[cfg(feature = "jvm-callback-support")]
49 #[no_mangle]
destroy_rust_jvm_cookie(global_ref_boxed: jlong)50 extern "system" fn destroy_rust_jvm_cookie(global_ref_boxed: jlong) {
51 unsafe {
52 drop(Box::from_raw(global_ref_boxed as *mut GlobalRef));
53 }
54 }
55