use crate::{cast::Upcast, java::lang::Throwable, Error, Java, JavaObject, Local};
pub trait AsJRef<U> {
fn as_jref(&self) -> Nullable<&U>;
}
pub struct NullJRef;
pub type Nullable<T> = Result<T, NullJRef>;
impl<'jvm, T, U> AsJRef<U> for T
where
T: TryJDeref,
T::Java: Upcast<U>,
U: JavaObject,
{
fn as_jref(&self) -> Nullable<&U> {
let this = self.try_jderef()?;
Ok(unsafe { std::mem::transmute(this) })
}
}
pub trait TryJDeref {
type Java: JavaObject;
fn try_jderef(&self) -> Nullable<&Self::Java>;
}
pub trait JDeref: TryJDeref {
fn jderef(&self) -> &Self::Java;
}
impl<T> TryJDeref for &T
where
T: TryJDeref,
{
type Java = T::Java;
fn try_jderef(&self) -> Nullable<&T::Java> {
T::try_jderef(self)
}
}
impl<T> JDeref for &T
where
T: JDeref,
{
fn jderef(&self) -> &T::Java {
T::jderef(self)
}
}
impl<T> TryJDeref for Local<'_, T>
where
T: JavaObject,
{
type Java = T;
fn try_jderef(&self) -> Nullable<&T> {
Ok(self)
}
}
impl<T> JDeref for Local<'_, T>
where
T: JavaObject,
{
fn jderef(&self) -> &T {
self
}
}
impl<T> TryJDeref for Java<T>
where
T: JavaObject,
{
type Java = T;
fn try_jderef(&self) -> Nullable<&T> {
Ok(self)
}
}
impl<T> JDeref for Java<T>
where
T: JavaObject,
{
fn jderef(&self) -> &T {
self
}
}
impl<T> TryJDeref for Option<T>
where
T: TryJDeref,
{
type Java = T::Java;
fn try_jderef(&self) -> Result<&T::Java, NullJRef> {
match self {
Some(r) => r.try_jderef(),
None => Err(NullJRef),
}
}
}
impl<T> From<NullJRef> for Error<T>
where
T: AsJRef<Throwable>,
{
fn from(NullJRef: NullJRef) -> Self {
Error::NullDeref
}
}