java_spaghetti/refs/
local.rs

1use std::fmt::{self, Debug, Display, Formatter};
2use std::ops::Deref;
3
4use jni_sys::*;
5
6use crate::{AssignableTo, Env, Global, Ref, ReferenceType, Return};
7
8/// A [Local](https://www.ibm.com/support/knowledgecenter/en/SSYKE2_8.0.0/com.ibm.java.vm.80.doc/docs/jni_refs.html),
9/// non-null, reference to a Java object (+ [Env]) limited to the current thread/stack.
10///
11/// Including the env allows for the convenient execution of methods without having to individually pass the env as an
12/// argument to each and every one.  Since this is limited to the current thread/stack, these cannot be sanely stored
13/// in any kind of static storage, nor shared between threads - instead use a [Global] if you need to do either.
14///
15/// Will `DeleteLocalRef` when dropped, invalidating the jobject but ensuring threads that rarely or never return to
16/// Java may run without being guaranteed to eventually exhaust their local reference limit.  If this is not desired,
17/// convert to a plain Ref with:
18///
19/// ```rust,no_run
20/// # use java_spaghetti::*;
21/// # fn example<T: ReferenceType>(local: Local<T>) {
22/// let local = Local::leak(local);
23/// # }
24/// ```
25///
26/// **Not FFI Safe:**  #\[repr(rust)\], and exact layout is likely to change - depending on exact features used - in the
27/// future.  Specifically, on Android, since we're guaranteed to only have a single ambient VM, we can likely store the
28/// \*const JNIEnv in thread local storage instead of lugging it around in every Local.  Of course, there's no
29/// guarantee that's actually an *optimization*...
30#[repr(transparent)]
31pub struct Local<'env, T: ReferenceType> {
32    ref_: Ref<'env, T>,
33}
34
35impl<'env, T: ReferenceType> Local<'env, T> {
36    pub unsafe fn from_raw(env: Env<'env>, object: jobject) -> Self {
37        Self {
38            ref_: Ref::from_raw(env, object),
39        }
40    }
41
42    pub fn env(&self) -> Env<'env> {
43        self.ref_.env()
44    }
45
46    pub fn as_raw(&self) -> jobject {
47        self.ref_.as_raw()
48    }
49
50    pub fn into_raw(self) -> jobject {
51        let object = self.ref_.as_raw();
52        std::mem::forget(self); // Don't allow local to DeleteLocalRef the jobject
53        object
54    }
55
56    pub fn leak(self) -> Ref<'env, T> {
57        let result = self.ref_;
58        std::mem::forget(self); // Don't allow local to DeleteLocalRef the jobject
59        result
60    }
61
62    pub fn as_global(&self) -> Global<T> {
63        let env = self.env();
64        let jnienv = env.as_raw();
65        let object = unsafe { ((**jnienv).v1_2.NewGlobalRef)(jnienv, self.as_raw()) };
66        unsafe { Global::from_raw(env.vm(), object) }
67    }
68
69    pub fn as_ref(&self) -> Ref<'_, T> {
70        self.ref_
71    }
72
73    pub fn as_return(&self) -> Return<'env, T> {
74        let env: *mut *const JNINativeInterface_ = self.env().as_raw();
75        let object = unsafe { ((**env).v1_2.NewLocalRef)(env, self.as_raw()) };
76        unsafe { Return::from_raw(object) }
77    }
78
79    pub fn into_return(self) -> Return<'env, T> {
80        unsafe { Return::from_raw(self.into_raw()) }
81    }
82
83    pub fn cast<U: ReferenceType>(&self) -> Result<Local<'env, U>, crate::CastError> {
84        let env = self.env();
85        let jnienv = env.as_raw();
86        let class1 = unsafe { ((**jnienv).v1_2.GetObjectClass)(jnienv, self.as_raw()) };
87        let class2 = U::static_with_jni_type(|t| unsafe { env.require_class(t) });
88        if !unsafe { ((**jnienv).v1_2.IsAssignableFrom)(jnienv, class1, class2) } {
89            return Err(crate::CastError);
90        }
91        let object = unsafe { ((**jnienv).v1_2.NewLocalRef)(jnienv, self.as_raw()) };
92        Ok(unsafe { Local::from_raw(env, object) })
93    }
94
95    pub fn upcast<U: ReferenceType>(&self) -> Local<'env, U>
96    where
97        Self: AssignableTo<U>,
98    {
99        let env = self.env();
100        let jnienv = env.as_raw();
101        let object = unsafe { ((**jnienv).v1_2.NewLocalRef)(jnienv, self.as_raw()) };
102        unsafe { Local::from_raw(env, object) }
103    }
104}
105
106impl<'env, T: ReferenceType> From<Ref<'env, T>> for Local<'env, T> {
107    fn from(x: Ref<'env, T>) -> Self {
108        x.as_local()
109    }
110}
111
112impl<'env, T: ReferenceType> From<&Local<'env, T>> for Local<'env, T> {
113    fn from(x: &Local<'env, T>) -> Self {
114        x.clone()
115    }
116}
117
118impl<'env, T: ReferenceType> From<&Ref<'env, T>> for Local<'env, T> {
119    fn from(x: &Ref<'env, T>) -> Self {
120        x.as_local()
121    }
122}
123
124impl<'env, T: ReferenceType> Deref for Local<'env, T> {
125    type Target = T;
126    fn deref(&self) -> &Self::Target {
127        unsafe { &*(self as *const Self as *const Self::Target) }
128    }
129}
130
131impl<'env, T: ReferenceType> Clone for Local<'env, T> {
132    fn clone(&self) -> Self {
133        let env = self.env().as_raw();
134        let object = unsafe { ((**env).v1_2.NewLocalRef)(env, self.as_raw()) };
135        unsafe { Self::from_raw(self.env(), object) }
136    }
137}
138
139impl<'env, T: ReferenceType> Drop for Local<'env, T> {
140    fn drop(&mut self) {
141        let env = self.env().as_raw();
142        unsafe { ((**env).v1_2.DeleteLocalRef)(env, self.as_raw()) }
143    }
144}
145
146impl<'env, T: ReferenceType + Debug> Debug for Local<'env, T> {
147    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
148        (**self).fmt(f)
149    }
150}
151
152impl<'env, T: ReferenceType + Display> Display for Local<'env, T> {
153    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
154        (**self).fmt(f)
155    }
156}