use super::*;
use std::marker::*;
use std::ops::*;
pub trait PrimitiveArray<T> where Self : Sized + AsValidJObjectAndEnv, T : Clone + Default {
fn new<'env>(env: &'env Env, size: usize) -> Local<'env, Self>;
fn len(&self) -> usize;
fn get_region(&self, start: usize, elements: &mut [T]);
fn set_region(&self, start: usize, elements: &[T]);
fn from<'env>(env: &'env Env, elements: &[T]) -> Local<'env, Self> {
let array = Self::new(env, elements.len());
array.set_region(0, elements);
array
}
fn get_region_as_vec(&self, range: impl RangeBounds<usize>) -> Vec<T> {
let len = self.len();
let start = match range.start_bound() {
Bound::Unbounded => 0,
Bound::Included(n) => *n,
Bound::Excluded(n) => *n+1,
};
let end = match range.end_bound() {
Bound::Unbounded => len,
Bound::Included(n) => *n+1,
Bound::Excluded(n) => *n,
};
assert!(start <= end);
assert!(end <= len);
let vec_len = end - start;
let mut vec = Vec::new();
vec.resize(vec_len, Default::default());
self.get_region(start, &mut vec[..]);
vec
}
fn as_vec(&self) -> Vec<T> {
self.get_region_as_vec(0..self.len())
}
}
#[test] fn bool_ffi_assumptions_test() {
use std::mem::*;
assert_eq!(size_of::<jboolean>(), 1);
assert_eq!(size_of::<bool>(), 1);
assert_eq!(unsafe { std::mem::transmute::<bool, u8>(true ) }, JNI_TRUE );
assert_eq!(unsafe { std::mem::transmute::<bool, u8>(false) }, JNI_FALSE);
}
macro_rules! primitive_array {
(#[repr(transparent)] pub struct $name:ident = $type_str:expr, $type:ident { $new_array:ident $set_region:ident $get_region:ident } ) => {
#[repr(transparent)] pub struct $name(ObjectAndEnv);
unsafe impl AsValidJObjectAndEnv for $name {}
unsafe impl AsJValue for $name { fn as_jvalue(&self) -> jni_sys::jvalue { jni_sys::jvalue { l: self.0.object } } }
unsafe impl JniType for $name { fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R { callback($type_str) } }
impl PrimitiveArray<$type> for $name {
fn new<'env>(env: &'env Env, size: usize) -> Local<'env, Self> {
assert!(size <= std::i32::MAX as usize);
let size = size as jsize;
let env = env.as_jni_env();
unsafe {
let object = (**env).$new_array.unwrap()(env, size);
let exception = (**env).ExceptionOccurred.unwrap()(env);
assert!(exception.is_null());
Local::from_env_object(env, object)
}
}
fn from<'env>(env: &'env Env, elements: &[$type]) -> Local<'env, Self> {
let array = Self::new(env, elements.len());
let size = elements.len() as jsize;
let env = array.0.env as *mut JNIEnv;
let object = array.0.object;
unsafe {
(**env).$set_region.unwrap()(env, object, 0, size, elements.as_ptr() as *const _);
}
array
}
fn len(&self) -> usize {
unsafe { (**self.0.env).GetArrayLength.unwrap()(self.0.env as *mut _, self.0.object) as usize }
}
fn get_region(&self, start: usize, elements: &mut [$type]) {
assert!(start <= std::i32::MAX as usize);
assert!(elements.len() <= std::i32::MAX as usize);
let self_len = self.len() as jsize;
let elements_len = elements.len() as jsize;
let start = start as jsize;
let end = start + elements_len;
assert!(start <= end);
assert!(end <= self_len);
unsafe { (**self.0.env).$get_region.unwrap()(self.0.env as *mut _, self.0.object, start, elements_len, elements.as_mut_ptr() as *mut _) };
}
fn set_region(&self, start: usize, elements: &[$type]) {
assert!(start <= std::i32::MAX as usize);
assert!(elements.len() <= std::i32::MAX as usize);
let self_len = self.len() as jsize;
let elements_len = elements.len() as jsize;
let start = start as jsize;
let end = start + elements_len;
assert!(start <= end);
assert!(end <= self_len);
unsafe { (**self.0.env).$set_region.unwrap()(self.0.env as *mut _, self.0.object, start, elements_len, elements.as_ptr() as *const _) };
}
}
};
}
primitive_array! { #[repr(transparent)] pub struct BooleanArray = "[Z\0", bool { NewBooleanArray SetBooleanArrayRegion GetBooleanArrayRegion } }
primitive_array! { #[repr(transparent)] pub struct ByteArray = "[B\0", jbyte { NewByteArray SetByteArrayRegion GetByteArrayRegion } }
primitive_array! { #[repr(transparent)] pub struct CharArray = "[C\0", jchar { NewCharArray SetCharArrayRegion GetCharArrayRegion } }
primitive_array! { #[repr(transparent)] pub struct ShortArray = "[S\0", jshort { NewShortArray SetShortArrayRegion GetShortArrayRegion } }
primitive_array! { #[repr(transparent)] pub struct IntArray = "[I\0", jint { NewIntArray SetIntArrayRegion GetIntArrayRegion } }
primitive_array! { #[repr(transparent)] pub struct LongArray = "[J\0", jlong { NewLongArray SetLongArrayRegion GetLongArrayRegion } }
primitive_array! { #[repr(transparent)] pub struct FloatArray = "[F\0", jfloat { NewFloatArray SetFloatArrayRegion GetFloatArrayRegion } }
primitive_array! { #[repr(transparent)] pub struct DoubleArray = "[D\0", jdouble { NewDoubleArray SetDoubleArrayRegion GetDoubleArrayRegion } }
#[repr(transparent)]
pub struct ObjectArray<T: AsValidJObjectAndEnv, E: ThrowableType>(ObjectAndEnv, PhantomData<(T,E)>);
unsafe impl<T: AsValidJObjectAndEnv, E: ThrowableType> AsValidJObjectAndEnv for ObjectArray<T, E> {}
unsafe impl<T: AsValidJObjectAndEnv, E: ThrowableType> JniType for ObjectArray<T, E> {
fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
T::static_with_jni_type(|inner| callback(format!("[{}", inner).as_str()))
}
}
unsafe impl<T: AsValidJObjectAndEnv, E: ThrowableType> AsJValue for ObjectArray<T, E> {
fn as_jvalue(&self) -> jni_sys::jvalue {
jni_sys::jvalue { l: self.0.object }
}
}
impl<T: AsValidJObjectAndEnv, E: ThrowableType> ObjectArray<T, E> {
pub fn new<'env>(env: &'env Env, size: usize) -> Local<'env, Self> {
assert!(size <= std::i32::MAX as usize);
let class = Self::static_with_jni_type(|t| unsafe { env.require_class(t) });
let size = size as jsize;
let env = env.as_jni_env();
unsafe {
let fill = null_mut();
let object = (**env).NewObjectArray.unwrap()(env, size, class, fill);
let exception = (**env).ExceptionOccurred.unwrap()(env);
assert!(exception.is_null());
Local::from_env_object(env, object)
}
}
pub fn iter<'env>(&'env self) -> ObjectArrayIter<'env, T, E> {
ObjectArrayIter {
array: self,
index: 0,
length: self.len(),
}
}
pub fn from<'env>(env: &'env Env, elements: impl 'env + ExactSizeIterator + Iterator<Item = impl Into<Option<&'env T>>>) -> Local<'env, Self> {
let size = elements.len();
let array = Self::new(env, size);
let env = array.0.env as *mut JNIEnv;
let this = array.0.object;
let set = unsafe { (**env) }.SetObjectArrayElement.unwrap();
for (index, element) in elements.enumerate() {
assert!(index < size);
let value = element.into().map(|v| unsafe { AsJValue::as_jvalue(v.into()).l }).unwrap_or(null_mut());
unsafe { set(env, this, index as jsize, value) };
}
array
}
pub fn len(&self) -> usize {
unsafe { (**self.0.env).GetArrayLength.unwrap()(self.0.env as *mut _, self.0.object) as usize }
}
pub fn get<'env>(&'env self, index: usize) -> Result<Option<Local<'env, T>>, Local<'env, E>> {
assert!(index <= std::i32::MAX as usize);
let index = index as jsize;
let env = self.0.env as *mut JNIEnv;
let this = self.0.object;
unsafe {
let result = (**env).GetObjectArrayElement.unwrap()(env, this, index);
let exception = (**env).ExceptionOccurred.unwrap()(env);
if !exception.is_null() {
(**env).ExceptionClear.unwrap()(env);
Err(Local::from_env_object(env, exception))
} else if result.is_null() {
Ok(None)
} else {
Ok(Some(Local::from_env_object(env, result)))
}
}
}
pub fn set<'env>(&'env self, index: usize, value: impl Into<Option<&'env T>>) -> Result<(), Local<'env, E>> {
assert!(index <= std::i32::MAX as usize);
let value = value.into().map(|v| unsafe { AsJValue::as_jvalue(v.into()).l }).unwrap_or(null_mut());
let index = index as jsize;
let env = self.0.env as *mut JNIEnv;
let this = self.0.object;
unsafe {
(**env).SetObjectArrayElement.unwrap()(env, this, index, value);
let exception = (**env).ExceptionOccurred.unwrap()(env);
if !exception.is_null() {
(**env).ExceptionClear.unwrap()(env);
Err(Local::from_env_object(env, exception))
} else {
Ok(())
}
}
}
}
pub struct ObjectArrayIter<'env, T: AsValidJObjectAndEnv, E: ThrowableType> {
array: &'env ObjectArray<T, E>,
index: usize,
length: usize,
}
impl<'env, T: AsValidJObjectAndEnv, E: ThrowableType> Iterator for ObjectArrayIter<'env, T, E> {
type Item = Option<Local<'env, T>>;
fn next(&mut self) -> Option<Self::Item> {
let index = self.index;
if index < self.length {
self.index = index + 1;
Some(self.array.get(index).unwrap_or(None))
} else {
None
}
}
}