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
use std::marker::PhantomData;

use crate::JniError;

#[derive(Clone)]
pub struct UniGlobalRef<T> {
	global_ref: jni::objects::GlobalRef,
	_p: PhantomData<T>,
}

// it's safe because JNI's GlobalRef can be
// accessable from any thread
unsafe impl<T> Send for UniGlobalRef<T> {
}


// it's probably safe if underlying java object is thread safe
// otherwise ther may be a race condition in case someone trying
// to access the java object concurently
unsafe impl<T> Sync for UniGlobalRef<T> {
}

impl<T> UniGlobalRef<T>
where
	T: Into<jni::objects::JObject<'static>>,
	T: From<jni::sys::jobject>,
{
	pub fn try_new<'b>(
		env: &jni::JNIEnv<'b>,
		obj: T,
	) -> Result<Self, JniError> {
		let global_ref = env.new_global_ref(obj.into())?;
		return Ok(Self {
			global_ref,
			_p: PhantomData,
		});
	}

	/// The method is unsafe because caller have to check if provided
	/// `wgr` pointing to the correct kind of object.
	pub unsafe fn try_upgrade<'b>(
		wgr: &jni::objects::WeakGlobalRef,
		env: &jni::JNIEnv<'b>,
	) -> Option<Self> {
		return match env.upgrade_weak_global_ref(wgr) {
			Err(e) => {
				crate::clear_exception(env, e);
				None
			},
			Ok(global_ref) => {
				match global_ref.as_obj().clone().into_inner().is_null() {
					true => None,
					false => {
						Some(Self {
							global_ref,
							_p: PhantomData,
						})
					},
				}
			},
		};
	}

	pub fn as_obj(&self) -> T {
		return self.global_ref.as_obj().into_inner().into();
	}
}