java_spaghetti/refs/
ref_.rs

1use std::fmt::{self, Debug, Display, Formatter};
2use std::marker::PhantomData;
3use std::ops::Deref;
4
5use jni_sys::jobject;
6
7use crate::{AssignableTo, Env, Global, Local, ObjectAndEnv, ReferenceType};
8
9/// A non-null, [reference](https://www.ibm.com/support/knowledgecenter/en/SSYKE2_8.0.0/com.ibm.java.vm.80.doc/docs/jni_refs.html)
10/// to a Java object (+ [Env]).  This may refer to a [Local](crate::Local), [Global](crate::Global), local [Arg](crate::Arg), etc.
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 JNIEnv in thread local storage instead of lugging it around in every Local.  Of course, there's no
15/// guarantee that's actually an *optimization*...
16#[repr(transparent)]
17pub struct Ref<'env, T: ReferenceType> {
18    oae: ObjectAndEnv,
19    _env: PhantomData<Env<'env>>,
20    _class: PhantomData<&'env T>,
21}
22
23impl<'env, T: ReferenceType> Copy for Ref<'env, T> {}
24impl<'env, T: ReferenceType> Clone for Ref<'env, T> {
25    fn clone(&self) -> Self {
26        Self {
27            oae: self.oae,
28            _env: PhantomData,
29            _class: PhantomData,
30        }
31    }
32}
33
34impl<'env, T: ReferenceType> Ref<'env, T> {
35    pub unsafe fn from_raw(env: Env<'env>, object: jobject) -> Self {
36        Self {
37            oae: ObjectAndEnv {
38                object,
39                env: env.as_raw(),
40            },
41            _env: PhantomData,
42            _class: PhantomData,
43        }
44    }
45
46    pub fn env(&self) -> Env<'env> {
47        unsafe { Env::from_raw(self.oae.env) }
48    }
49
50    pub fn as_raw(&self) -> jobject {
51        self.oae.object
52    }
53
54    pub fn as_global(&self) -> Global<T> {
55        let env = self.env();
56        let jnienv = env.as_raw();
57        let object = unsafe { ((**jnienv).v1_2.NewGlobalRef)(jnienv, self.as_raw()) };
58        unsafe { Global::from_raw(env.vm(), object) }
59    }
60
61    pub fn as_local(&self) -> Local<'env, T> {
62        let env = self.env();
63        let jnienv = env.as_raw();
64        let object = unsafe { ((**jnienv).v1_2.NewLocalRef)(jnienv, self.as_raw()) };
65        unsafe { Local::from_raw(self.env(), object) }
66    }
67
68    pub fn cast<U: ReferenceType>(&self) -> Result<Ref<'env, U>, crate::CastError> {
69        let env = self.env();
70        let jnienv = env.as_raw();
71        let class1 = unsafe { ((**jnienv).v1_2.GetObjectClass)(jnienv, self.as_raw()) };
72        let class2 = U::static_with_jni_type(|t| unsafe { env.require_class(t) });
73        if !unsafe { ((**jnienv).v1_2.IsAssignableFrom)(jnienv, class1, class2) } {
74            return Err(crate::CastError);
75        }
76        Ok(unsafe { Ref::from_raw(env, self.as_raw()) })
77    }
78
79    pub fn upcast<U: ReferenceType>(&self) -> Ref<'env, U>
80    where
81        Self: AssignableTo<U>,
82    {
83        let env = self.env();
84        unsafe { Ref::from_raw(env, self.as_raw()) }
85    }
86}
87
88impl<'env, T: ReferenceType> Deref for Ref<'env, T> {
89    type Target = T;
90    fn deref(&self) -> &Self::Target {
91        unsafe { &*(&self.oae as *const ObjectAndEnv as *const Self::Target) }
92    }
93}
94
95impl<'env, T: ReferenceType + Debug> Debug for Ref<'env, T> {
96    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
97        (**self).fmt(f)
98    }
99}
100
101impl<'env, T: ReferenceType + Display> Display for Ref<'env, T> {
102    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
103        (**self).fmt(f)
104    }
105}