java_oxide/refs/global.rs
1use crate::{Env, Local, Ref, ReferenceType, VM};
2use jni_sys::*;
3use std::marker::PhantomData;
4
5/// A [Global](https://www.ibm.com/docs/en/sdk-java-technology/8?topic=collector-overview-jni-object-references),
6/// non-null, reference to a Java object (+ [VM]).
7///
8/// Unlike Local, this can be stored statically and shared between threads. This has a few caveats:
9/// * You must create a [Ref] before use.
10/// * The [Global] can be invalidated if the [VM] is unloaded.
11///
12/// **Not FFI Safe:** `#[repr(rust)]`, and exact layout is likely to change - depending on exact features used - in the
13/// future. Specifically, on Android, since we're guaranteed to only have a single ambient VM, we can likely store the
14/// `*const JavaVM` in static and/or thread local storage instead of lugging it around in every [Global]. Of course, there's
15/// no guarantee that's actually an *optimization*...
16pub struct Global<T: ReferenceType> {
17 object: jobject,
18 vm: VM,
19 pd: PhantomData<T>,
20}
21
22unsafe impl<T: ReferenceType> Send for Global<T> {}
23unsafe impl<T: ReferenceType> Sync for Global<T> {}
24
25impl<T: ReferenceType> Global<T> {
26 /// Wraps an owned raw JNI global reference, taking the ownership.
27 ///
28 /// # Safety
29 ///
30 /// `object` must be an owned non-null JNI global reference to an object of type `T`,
31 /// not to be deleted by another wrapper.
32 pub unsafe fn from_raw(vm: VM, object: jobject) -> Self {
33 Self {
34 object,
35 vm,
36 pd: PhantomData,
37 }
38 }
39
40 /// Gets the [VM] under which the JNI reference is created.
41 pub fn vm(&self) -> VM {
42 self.vm
43 }
44
45 /// Returns the raw JNI reference pointer.
46 pub fn as_raw(&self) -> jobject {
47 self.object
48 }
49
50 /// Leaks the `Global` and turns it into a raw pointer, preserving the ownership of
51 /// one JNI global reference; prevents `DeleteGlobalRef` from being called on dropping.
52 pub fn into_raw(self) -> jobject {
53 let object = self.object;
54 std::mem::forget(self); // Don't delete the object.
55 object
56 }
57
58 /// Returns a new JNI local reference of the same Java object.
59 pub fn as_local<'env>(&self, env: Env<'env>) -> Local<'env, T> {
60 // Safety: this `Ref<'env, T>` isn't available outside, and it does nothing on dropping.
61 let temp_ref = unsafe { Ref::from_raw(env, self.object) };
62 temp_ref.as_local() // creates a new `Local`
63 }
64
65 /// Returns a [Ref], with which Java methods from generated bindings can be used.
66 /// The lifetime of the returned [Ref] can be the intersection of this `Global`
67 /// and a supposed local reference under `env`.
68 pub fn as_ref<'env>(&'env self, env: Env<'env>) -> Ref<'env, T> {
69 unsafe { Ref::from_raw(env, self.object) }
70 }
71}
72
73impl<'env, T: ReferenceType> From<Local<'env, T>> for Global<T> {
74 fn from(x: Local<'env, T>) -> Self {
75 x.as_global()
76 }
77}
78
79impl<'env, T: ReferenceType> From<Ref<'env, T>> for Global<T> {
80 fn from(x: Ref<'env, T>) -> Self {
81 x.as_global()
82 }
83}
84
85impl<'env, T: ReferenceType> From<&Local<'env, T>> for Global<T> {
86 fn from(x: &Local<'env, T>) -> Self {
87 x.as_global()
88 }
89}
90
91impl<'env, T: ReferenceType> From<&Ref<'env, T>> for Global<T> {
92 fn from(x: &Ref<'env, T>) -> Self {
93 x.as_global()
94 }
95}
96
97impl<T: ReferenceType> Clone for Global<T> {
98 fn clone(&self) -> Self {
99 self.vm.with_env(|env| {
100 let env = env.as_raw();
101 let object = unsafe { ((**env).v1_2.NewGlobalRef)(env, self.object) };
102 assert!(!object.is_null());
103 Self {
104 object,
105 vm: self.vm,
106 pd: PhantomData,
107 }
108 })
109 }
110}
111
112impl<T: ReferenceType> Drop for Global<T> {
113 fn drop(&mut self) {
114 self.vm.with_env(|env| {
115 let env = env.as_raw();
116 unsafe { ((**env).v1_2.DeleteGlobalRef)(env, self.object) }
117 });
118 }
119}