1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
use super::*; /// A [Global](https://www.ibm.com/support/knowledgecenter/en/SSYKE2_8.0.0/com.ibm.java.vm.80.doc/docs/jni_refs.html), /// non-null, reference to a Java object (+ &[VM]). /// /// Unlike Local, this can be stored statically and shared between threads. This has a few caveats: /// * You must create a [GlobalRef] before use. /// * The [Global] can be invalidated if the [VM] is unloaded. /// /// **Not FFI Safe:** #\[repr(rust)\], and exact layout is likely to change - depending on exact features used - in the /// future. Specifically, on Android, since we're guaranteed to only have a single ambient [VM], we can likely store the /// *const JavaVM in static and/or thread local storage instead of lugging it around in every [Local]. Of course, there's /// no guarantee that's actually an *optimization*... /// /// [VM]: struct.VM.html /// [Global]: struct.Global.html /// [GlobalRef]: type.GlobalRef.html pub struct Global<Class: AsValidJObjectAndEnv> { pub(crate) global: jobject, pub(crate) gen_vm: GenVM, pub(crate) pd: PhantomData<Class>, } unsafe impl<Class: AsValidJObjectAndEnv> Send for Global<Class> {} unsafe impl<Class: AsValidJObjectAndEnv> Sync for Global<Class> {} impl<Class: AsValidJObjectAndEnv> Global<Class> { pub fn with<'env>(&'env self, env: &'env Env) -> GlobalRef<'env, Class> { assert_eq!(self.gen_vm, env.get_gen_vm()); // Soundness check - env *must* belong to the same VM! unsafe { self.with_unchecked(env) } } pub unsafe fn with_unchecked<'env>(&'env self, env: &'env Env) -> GlobalRef<'env, Class> { let env = env.as_jni_env(); GlobalRef { oae: ObjectAndEnv { object: self.global, env, }, _env: PhantomData, _class: PhantomData, } } } impl<'env, Class: AsValidJObjectAndEnv> From<Local<'env, Class>> for Global<Class> { fn from(local: Local<'env, Class>) -> Global<Class> { let env = unsafe { Env::from_ptr(local.oae.env) }; let jnienv = env.as_jni_env(); let gen_vm = env.get_gen_vm(); let global = unsafe { (**jnienv).NewGlobalRef.unwrap()(jnienv, local.oae.object) }; Global { global, gen_vm, pd: PhantomData, } } } impl<Class: AsValidJObjectAndEnv> Drop for Global<Class> { fn drop(&mut self) { VMS.read().unwrap().use_vm(self.gen_vm, |vm|{ vm.with_env(|env|{ let env = env.as_jni_env(); unsafe { (**env).DeleteGlobalRef.unwrap()(env, self.global); } }); }); } } /// A [Global](https://www.ibm.com/support/knowledgecenter/en/SSYKE2_8.0.0/com.ibm.java.vm.80.doc/docs/jni_refs.html), /// non-null, reference to a Java object (+ &Env). /// /// Much like Local, the inclusion of an Env means this cannot be stored statically or shared between threads. /// /// **Not FFI Safe:** #\[repr(rust)\], and exact layout is likely to change - depending on exact features used - in the /// future. Specifically, on Android, since we're guaranteed to only have a single ambient VM, we can likely store the /// \*const JNIEnv in thread local storage instead of lugging it around in every Local. Of course, there's no /// guarantee that's actually an *optimization*... pub type GlobalRef<'env, Class> = Ref<'env, Class>;