use std::{mem, ops::Deref, sync::Arc};
use log::{debug, warn};
use crate::{errors::Result, objects::JObject, sys, JNIEnv, JavaVM};
#[derive(Clone, Debug)]
pub struct GlobalRef {
inner: Arc<GlobalRefGuard>,
}
#[derive(Debug)]
struct GlobalRefGuard {
obj: JObject<'static>,
vm: JavaVM,
}
impl AsRef<GlobalRef> for GlobalRef {
fn as_ref(&self) -> &GlobalRef {
self
}
}
impl AsRef<JObject<'static>> for GlobalRef {
fn as_ref(&self) -> &JObject<'static> {
self
}
}
impl Deref for GlobalRef {
type Target = JObject<'static>;
fn deref(&self) -> &Self::Target {
&self.inner.obj
}
}
impl GlobalRef {
pub(crate) unsafe fn from_raw(vm: JavaVM, raw_global_ref: sys::jobject) -> Self {
GlobalRef {
inner: Arc::new(GlobalRefGuard::from_raw(vm, raw_global_ref)),
}
}
pub fn as_obj(&self) -> &JObject<'static> {
self.as_ref()
}
}
impl GlobalRefGuard {
unsafe fn from_raw(vm: JavaVM, obj: sys::jobject) -> Self {
GlobalRefGuard {
obj: JObject::from_raw(obj),
vm,
}
}
}
impl Drop for GlobalRefGuard {
fn drop(&mut self) {
let raw: sys::jobject = mem::take(&mut self.obj).into_raw();
let drop_impl = |env: &JNIEnv| -> Result<()> {
let internal = env.get_native_interface();
jni_unchecked!(internal, DeleteGlobalRef, raw);
Ok(())
};
let res = match self.vm.get_env() {
Ok(env) => drop_impl(&env),
Err(_) => {
warn!("Dropping a GlobalRef in a detached thread. Fix your code if this message appears frequently (see the GlobalRef docs).");
self.vm
.attach_current_thread()
.and_then(|env| drop_impl(&env))
}
};
if let Err(err) = res {
debug!("error dropping global ref: {:#?}", err);
}
}
}