use crate::{
errors::*,
objects::{JMethodID, JObject},
signature::{JavaType, Primitive},
sys::jint,
JNIEnv,
};
pub struct JList<'a: 'b, 'b> {
internal: JObject<'a>,
get: JMethodID<'a>,
add: JMethodID<'a>,
add_idx: JMethodID<'a>,
remove: JMethodID<'a>,
size: JMethodID<'a>,
env: &'b JNIEnv<'a>,
}
impl<'a: 'b, 'b> ::std::ops::Deref for JList<'a, 'b> {
type Target = JObject<'a>;
fn deref(&self) -> &Self::Target {
&self.internal
}
}
impl<'a: 'b, 'b> From<JList<'a, 'b>> for JObject<'a> {
fn from(other: JList<'a, 'b>) -> JObject<'a> {
other.internal
}
}
impl<'a: 'b, 'b> JList<'a, 'b> {
pub fn from_env(env: &'b JNIEnv<'a>, obj: JObject<'a>) -> Result<JList<'a, 'b>> {
let class = env.auto_local(env.find_class("java/util/List")?);
let get = env.get_method_id(&class, "get", "(I)Ljava/lang/Object;")?;
let add = env.get_method_id(&class, "add", "(Ljava/lang/Object;)Z")?;
let add_idx = env.get_method_id(&class, "add", "(ILjava/lang/Object;)V")?;
let remove = env.get_method_id(&class, "remove", "(I)Ljava/lang/Object;")?;
let size = env.get_method_id(&class, "size", "()I")?;
Ok(JList {
internal: obj,
get,
add,
add_idx,
remove,
size,
env,
})
}
pub fn get(&self, idx: jint) -> Result<Option<JObject<'a>>> {
let result = self.env.call_method_unchecked(
self.internal,
self.get,
JavaType::Object("java/lang/Object".into()),
&[idx.into()],
);
match result {
Ok(val) => Ok(Some(val.l()?)),
Err(e) => match e {
Error::NullPtr(_) => Ok(None),
_ => Err(e),
},
}
}
pub fn add(&self, value: JObject<'a>) -> Result<()> {
let result = self.env.call_method_unchecked(
self.internal,
self.add,
JavaType::Primitive(Primitive::Boolean),
&[value.into()],
);
let _ = result?;
Ok(())
}
pub fn insert(&self, idx: jint, value: JObject<'a>) -> Result<()> {
let result = self.env.call_method_unchecked(
self.internal,
self.add_idx,
JavaType::Primitive(Primitive::Void),
&[idx.into(), value.into()],
);
let _ = result?;
Ok(())
}
pub fn remove(&self, idx: jint) -> Result<Option<JObject<'a>>> {
let result = self.env.call_method_unchecked(
self.internal,
self.remove,
JavaType::Object("java/lang/Object".into()),
&[idx.into()],
);
match result {
Ok(val) => Ok(Some(val.l()?)),
Err(e) => match e {
Error::NullPtr(_) => Ok(None),
_ => Err(e),
},
}
}
pub fn size(&self) -> Result<jint> {
let result = self.env.call_method_unchecked(
self.internal,
self.size,
JavaType::Primitive(Primitive::Int),
&[],
);
result.and_then(|v| v.i())
}
pub fn pop(&self) -> Result<Option<JObject<'a>>> {
let size = self.size()?;
if size == 0 {
return Ok(None);
}
let result = self.env.call_method_unchecked(
self.internal,
self.remove,
JavaType::Object("java/lang/Object".into()),
&[(size - 1).into()],
);
match result {
Ok(val) => Ok(Some(val.l()?)),
Err(e) => match e {
Error::NullPtr(_) => Ok(None),
_ => Err(e),
},
}
}
pub fn iter(&self) -> Result<JListIter<'a, 'b, '_>> {
Ok(JListIter {
list: &self,
current: 0,
size: self.size()?,
})
}
}
pub struct JListIter<'a: 'b, 'b: 'c, 'c> {
list: &'c JList<'a, 'b>,
current: jint,
size: jint,
}
impl<'a: 'b, 'b: 'c, 'c> Iterator for JListIter<'a, 'b, 'c> {
type Item = JObject<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.current == self.size {
return None;
}
let res = self.list.get(self.current);
match res {
Ok(elem) => {
self.current += 1;
elem
}
Err(_) => {
self.current = self.size;
None
}
}
}
}