1use crate::{AssignableTo, Env, Global, JavaDebug, JavaDisplay, Local, ReferenceType};
2use jni_sys::jobject;
3use std::{
4 fmt::{self, Debug, Display, Formatter},
5 marker::PhantomData,
6 mem::transmute,
7 ops::Deref,
8};
9
10#[repr(C)] pub struct Ref<'env, T: ReferenceType> {
21 object: jobject,
22 env: Env<'env>,
23 _class: PhantomData<T>,
24}
25
26impl<'env, T: ReferenceType> std::ops::Receiver for Ref<'env, T> {
27 type Target = T;
28}
29
30impl<'env, T: ReferenceType> Ref<'env, T> {
31 pub unsafe fn from_raw(env: Env<'env>, object: jobject) -> Self {
39 Self {
40 object,
41 env,
42 _class: PhantomData,
43 }
44 }
45
46 pub fn env(&self) -> Env<'env> {
48 self.env
49 }
50
51 pub fn as_raw(&self) -> jobject {
53 self.object
54 }
55
56 pub fn as_global(&self) -> Global<T> {
58 let env = self.env();
59 let jnienv = env.as_raw();
60 let object = unsafe { ((**jnienv).v1_2.NewGlobalRef)(jnienv, self.as_raw()) };
61 assert!(!object.is_null());
62 unsafe { Global::from_raw(env.vm(), object) }
63 }
64
65 pub fn as_local(&self) -> Local<'env, T> {
67 let env = self.env();
68 let jnienv = env.as_raw();
69 let object = unsafe { ((**jnienv).v1_2.NewLocalRef)(jnienv, self.as_raw()) };
70 assert!(!object.is_null());
71 unsafe { Local::from_raw(self.env(), object) }
72 }
73
74 pub fn as_monitor(&'env self) -> Monitor<'env, T> {
77 Monitor::new(self)
78 }
79
80 pub fn is_same_object<O: ReferenceType>(&self, other: &Ref<'_, O>) -> bool {
82 let jnienv = self.env.as_raw();
83 unsafe { ((**jnienv).v1_2.IsSameObject)(jnienv, self.as_raw(), other.as_raw()) }
84 }
85
86 pub(crate) fn check_assignable<U: ReferenceType>(&self) -> Result<(), crate::CastError> {
88 let env = self.env();
89 let jnienv = env.as_raw();
90 let class = U::static_with_jni_type(|t| unsafe { env.require_class(t) });
91 let assignable = unsafe { ((**jnienv).v1_2.IsInstanceOf)(jnienv, self.as_raw(), class) };
92 unsafe {
93 ((**jnienv).v1_2.DeleteLocalRef)(jnienv, class);
94 }
95 if assignable {
96 Ok(())
97 } else {
98 Err(crate::CastError)
99 }
100 }
101
102 pub unsafe fn cast_unchecked<U: ReferenceType>(self) -> Ref<'env, U> {
108 unsafe { transmute(self) }
109 }
110
111 pub fn cast<U: ReferenceType>(self) -> Result<Ref<'env, U>, crate::CastError> {
113 self.check_assignable::<U>()?;
114 Ok(unsafe { self.cast_unchecked() })
115 }
116
117 pub fn upcast<U: ReferenceType>(self) -> Ref<'env, U>
119 where
120 T: AssignableTo<U>,
121 {
122 unsafe { self.cast_unchecked() }
123 }
124
125 pub unsafe fn cast_ref_unchecked<U: ReferenceType>(&self) -> &Ref<'env, U> {
131 unsafe { transmute(self) }
132 }
133
134 pub fn cast_ref<U: ReferenceType>(&self) -> Result<&Ref<'env, U>, crate::CastError> {
136 self.check_assignable::<U>()?;
137 Ok(unsafe { self.cast_ref_unchecked() })
138 }
139
140 pub fn upcast_ref<U: ReferenceType>(&self) -> &Ref<'env, U>
142 where
143 T: AssignableTo<U>,
144 {
145 unsafe { self.cast_ref_unchecked() }
146 }
147}
148
149impl<'env, T: JavaDebug> Debug for Ref<'env, T> {
150 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
151 T::fmt(self, f)
152 }
153}
154
155impl<'env, T: JavaDisplay> Display for Ref<'env, T> {
156 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
157 T::fmt(self, f)
158 }
159}
160
161pub struct Monitor<'env, T: ReferenceType> {
172 inner: &'env Ref<'env, T>,
173}
174
175impl<'env, T: ReferenceType> Monitor<'env, T> {
176 fn new(reference: &'env Ref<'env, T>) -> Self {
177 let jnienv = reference.env.as_raw();
178 let result = unsafe { ((**jnienv).v1_2.MonitorEnter)(jnienv, reference.as_raw()) };
179 assert!(result == jni_sys::JNI_OK);
180 Self { inner: reference }
181 }
182
183 pub fn unlock(self) -> &'env Ref<'env, T> {
186 let inner = self.inner;
187 drop(self); inner
189 }
190}
191
192impl<'env, T: ReferenceType> Deref for Monitor<'env, T> {
193 type Target = Ref<'env, T>;
194 fn deref(&self) -> &Self::Target {
195 self.inner
196 }
197}
198
199impl<'env, T: ReferenceType> Drop for Monitor<'env, T> {
200 fn drop(&mut self) {
201 let env = self.inner.env;
202 let jnienv = env.as_raw();
203 let result = unsafe { ((**jnienv).v1_2.MonitorExit)(jnienv, self.inner.as_raw()) };
204 assert!(result == jni_sys::JNI_OK);
205 let exception = unsafe { ((**jnienv).v1_2.ExceptionOccurred)(jnienv) };
206 assert!(
207 exception.is_null(),
208 "exception happened calling JNI MonitorExit, the monitor is probably broken previously"
209 );
210 }
211}