use std::{borrow::Cow, marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr};
use jni_sys::jobject;
use crate::{
Env, JavaVM, errors,
objects::{Global, JClass, JObject, LoaderContext},
strings::JNIStr,
};
use super::Reference;
#[derive(Debug)]
pub struct Auto<'local, T>
where
T: Into<JObject<'local>>,
{
obj: ManuallyDrop<T>,
_lifetime: PhantomData<&'local T>,
}
#[deprecated(since = "0.22.0", note = "AutoLocal has been renamed to `Auto`")]
pub type AutoLocal<'local, T> = Auto<'local, T>;
impl<'local, T> Auto<'local, T>
where
T: Into<JObject<'local>>,
{
pub fn new(obj: T) -> Self {
Auto {
obj: ManuallyDrop::new(obj),
_lifetime: PhantomData,
}
}
pub fn unwrap(self) -> T {
let self_md = ManuallyDrop::new(self);
unsafe {
ptr::read(&*self_md.obj)
}
}
#[deprecated = "Renamed to Auto::unwrap"]
pub fn forget(self) -> T {
self.unwrap()
}
}
impl<'local, T> Drop for Auto<'local, T>
where
T: Into<JObject<'local>>,
{
fn drop(&mut self) {
let obj = unsafe { ManuallyDrop::take(&mut self.obj) };
let obj: JObject = obj.into();
if !obj.is_null() {
let Ok(vm) = JavaVM::singleton() else {
log::error!("Failed to drop Auto: No JavaVM initialized");
return;
};
vm.with_top_local_frame(|env| -> errors::Result<()> {
env.delete_local_ref(obj);
Ok(())
})
.expect("Infallible"); }
}
}
impl<'local, T, U> AsRef<U> for Auto<'local, T>
where
T: AsRef<U> + Into<JObject<'local>>,
{
fn as_ref(&self) -> &U {
self.obj.as_ref()
}
}
impl<'local, T> Deref for Auto<'local, T>
where
T: Into<JObject<'local>>,
{
type Target = T;
fn deref(&self) -> &Self::Target {
&self.obj
}
}
pub trait IntoAuto<'local>: Sized + Into<JObject<'local>> {
fn auto(self) -> Auto<'local, Self> {
Auto::new(self)
}
}
impl<'local, T> IntoAuto<'local> for T where T: Into<JObject<'local>> {}
impl<'local, T> From<T> for Auto<'local, T>
where
T: Into<JObject<'local>>,
{
fn from(value: T) -> Self {
Auto::new(value)
}
}
unsafe impl<'local, T> Reference for Auto<'local, T>
where
T: Reference + Into<JObject<'local>>,
{
type Kind<'env> = T::Kind<'env>;
type GlobalKind = T::GlobalKind;
fn as_raw(&self) -> jobject {
self.obj.as_raw()
}
fn class_name() -> Cow<'static, JNIStr> {
T::class_name()
}
fn lookup_class<'caller>(
env: &Env<'_>,
loader_context: &LoaderContext,
) -> crate::errors::Result<impl Deref<Target = Global<JClass<'static>>> + 'caller> {
T::lookup_class(env, loader_context)
}
unsafe fn kind_from_raw<'env>(local_ref: jobject) -> Self::Kind<'env> {
unsafe { T::kind_from_raw(local_ref) }
}
unsafe fn global_kind_from_raw(global_ref: jobject) -> Self::GlobalKind {
unsafe { T::global_kind_from_raw(global_ref) }
}
}