use core::marker::PhantomData;
use std::str::FromStr;
use std::sync::RwLock;
use java::ResultExt;
use jni::objects::{JFieldID, JStaticFieldID};
use crate::java;
pub struct Field<C, T> {
name: &'static str,
id: RwLock<Option<JFieldID>>,
_t: PhantomData<(C, T)>,
}
impl<C, T> Field<C, T>
where C: java::Class,
T: java::Object
{
pub const fn new(name: &'static str) -> Self {
Self { name,
id: RwLock::new(None),
_t: PhantomData }
}
pub fn get(&self, e: &mut java::Env, inst: &C) -> T {
let id = self.id.read().unwrap();
if id.is_none() {
drop(id);
let mut id = self.id.write().unwrap();
*id = Some(e.get_field_id(C::PATH, self.name, T::SIG).unwrap_java(e));
drop(id);
self.get(e, inst)
} else {
let inst = inst.downcast_ref(e);
let val =
e.get_field_unchecked(&inst,
id.unwrap(),
jni::signature::ReturnType::from_str(T::SIG.as_str()).unwrap())
.unwrap_java(e);
T::upcast_value(e, val)
}
}
pub fn set(&self, e: &mut java::Env, inst: &C, t: T) {
let inst = inst.downcast_ref(e);
let t = t.downcast_value(e);
e.set_field(inst, self.name, T::SIG, (&t).into())
.unwrap_java(e);
}
}
pub struct StaticField<C, T> {
name: &'static str,
id: RwLock<Option<JStaticFieldID>>,
_t: PhantomData<(C, T)>,
}
impl<C, T> StaticField<C, T>
where C: java::Class,
T: java::Object
{
pub const fn new(name: &'static str) -> Self {
Self { name,
id: RwLock::new(None),
_t: PhantomData }
}
pub fn get(&self, e: &mut java::Env) -> T {
let id = self.id.read().unwrap();
if id.is_none() {
drop(id);
let mut id = self.id.write().unwrap();
*id = Some(e.get_static_field_id(C::PATH, self.name, T::SIG)
.unwrap_java(e));
drop(id);
self.get(e)
} else {
let val = e.get_static_field_unchecked(C::PATH, id.unwrap(), T::jni())
.unwrap();
T::upcast_value(e, val)
}
}
}