use std::borrow::Cow;
use std::marker::PhantomData;
use std::ops::Deref;
use crate::{
env::Env,
errors::Result,
objects::{
AutoElements, AutoElementsCritical, Global, JClass, JObject, LoaderContext, Reference,
ReleaseMode,
},
strings::JNIStr,
sys::{jarray, jobject},
};
use super::TypeArray;
#[cfg(doc)]
use crate::{MonitorGuard, errors::Error, objects::JObjectArray};
#[repr(transparent)]
#[derive(Debug)]
pub struct JPrimitiveArray<'local, T: TypeArray> {
obj: JObject<'local>,
_marker: PhantomData<T>,
}
impl<'local, T: TypeArray> AsRef<JPrimitiveArray<'local, T>> for JPrimitiveArray<'local, T> {
fn as_ref(&self) -> &JPrimitiveArray<'local, T> {
self
}
}
impl<'local, T: TypeArray> AsMut<JPrimitiveArray<'local, T>> for JPrimitiveArray<'local, T> {
fn as_mut(&mut self) -> &mut JPrimitiveArray<'local, T> {
self
}
}
impl<'local, T: TypeArray> AsRef<JObject<'local>> for JPrimitiveArray<'local, T> {
fn as_ref(&self) -> &JObject<'local> {
&self.obj
}
}
impl<'local, T: TypeArray> ::std::ops::Deref for JPrimitiveArray<'local, T> {
type Target = JObject<'local>;
fn deref(&self) -> &Self::Target {
&self.obj
}
}
impl<'local, T: TypeArray> From<JPrimitiveArray<'local, T>> for JObject<'local> {
fn from(other: JPrimitiveArray<'local, T>) -> JObject<'local> {
other.obj
}
}
impl<T: TypeArray> std::default::Default for JPrimitiveArray<'_, T> {
fn default() -> Self {
Self {
obj: JObject::null(),
_marker: PhantomData,
}
}
}
impl<'local, T: TypeArray> JPrimitiveArray<'local, T> {
pub fn new<'env_local>(
env: &mut Env<'env_local>,
length: usize,
) -> Result<JPrimitiveArray<'env_local, T>> {
if length > crate::sys::jsize::MAX as usize {
return Err(crate::errors::Error::JniCall(
crate::errors::JniError::InvalidArguments,
));
}
env.assert_top();
let raw_array = unsafe { T::new_array(env, length as crate::sys::jsize)? };
unsafe { Ok(JPrimitiveArray::from_raw(env, raw_array)) }
}
pub unsafe fn from_raw<'env_local>(
env: &Env<'env_local>,
raw: jarray,
) -> JPrimitiveArray<'env_local, T> {
JPrimitiveArray {
obj: unsafe { JObject::from_raw(env, raw as jobject) },
_marker: PhantomData,
}
}
pub const fn null() -> JPrimitiveArray<'static, T> {
JPrimitiveArray {
obj: JObject::null(),
_marker: PhantomData,
}
}
pub const fn into_raw(self) -> jarray {
self.obj.into_raw() as jarray
}
pub fn len(&self, env: &Env) -> Result<usize> {
let array = null_check!(self.as_raw(), "JPrimitiveArray::len self argument")?;
let len = unsafe { jni_call_no_post_check_ex!(env, v1_1, GetArrayLength, array)? } as usize;
Ok(len)
}
pub unsafe fn get_elements(
&self,
env: &Env,
mode: ReleaseMode,
) -> Result<AutoElements<'local, T, &Self>> {
AutoElements::new(env, self, mode)
}
pub unsafe fn get_elements_critical(
&self,
env: &Env<'_>,
mode: ReleaseMode,
) -> Result<AutoElementsCritical<'local, T, &Self>> {
AutoElementsCritical::new(env, self, mode)
}
pub fn get_region(&self, env: &Env, start: crate::sys::jsize, buf: &mut [T]) -> Result<()> {
unsafe { T::get_region(env, self.as_raw() as jarray, start, buf) }
}
pub fn set_region(&self, env: &Env, start: crate::sys::jsize, buf: &[T]) -> Result<()> {
unsafe { T::set_region(env, self.as_raw() as jarray, start, buf) }
}
}
pub type JBooleanArray<'local> = JPrimitiveArray<'local, crate::sys::jboolean>;
pub type JByteArray<'local> = JPrimitiveArray<'local, crate::sys::jbyte>;
pub type JCharArray<'local> = JPrimitiveArray<'local, crate::sys::jchar>;
pub type JShortArray<'local> = JPrimitiveArray<'local, crate::sys::jshort>;
pub type JIntArray<'local> = JPrimitiveArray<'local, crate::sys::jint>;
pub type JLongArray<'local> = JPrimitiveArray<'local, crate::sys::jlong>;
pub type JFloatArray<'local> = JPrimitiveArray<'local, crate::sys::jfloat>;
pub type JDoubleArray<'local> = JPrimitiveArray<'local, crate::sys::jdouble>;
pub unsafe trait AsJArrayRaw<'local>: AsRef<JObject<'local>> {
fn as_jarray_raw(&self) -> jarray {
self.as_ref().as_raw() as jarray
}
}
unsafe impl<'local, T: TypeArray> AsJArrayRaw<'local> for JPrimitiveArray<'local, T> {}
macro_rules! impl_ref_for_jprimitive_array {
($type:ident, $class_name:expr, $api_type:ident) => {
#[allow(non_camel_case_types)]
pub(crate) struct $api_type {
class: Global<JClass<'static>>,
}
impl $api_type {
pub(crate) fn get<'any_local>(
env: &Env<'_>,
loader_context: &LoaderContext<'any_local, '_>,
) -> Result<&'static Self> {
static API: std::sync::OnceLock<$api_type> = std::sync::OnceLock::new();
if let Some(api) = API.get() {
return Ok(api);
}
let api = env.with_local_frame(4, |env| -> Result<_> {
let class = loader_context
.load_class_for_type::<JPrimitiveArray<crate::sys::$type>>(env, false)?;
let class = env.new_global_ref(&class).unwrap();
Ok(Self { class })
})?;
let _ = API.set(api);
Ok(API.get().unwrap())
}
}
impl JPrimitiveArray<'_, crate::sys::$type> {
pub fn cast_local<'any_local>(
env: &mut Env<'_>,
obj: impl Reference + Into<JObject<'any_local>> + AsRef<JObject<'any_local>>,
) -> Result<
<JPrimitiveArray<'any_local, crate::sys::$type> as Reference>::Kind<'any_local>,
> {
env.cast_local::<JPrimitiveArray<crate::sys::$type>>(obj)
}
}
unsafe impl Reference for JPrimitiveArray<'_, crate::sys::$type> {
type Kind<'env> = JPrimitiveArray<'env, crate::sys::$type>;
type GlobalKind = JPrimitiveArray<'static, crate::sys::$type>;
fn as_raw(&self) -> jobject {
self.obj.as_raw()
}
fn class_name() -> Cow<'static, JNIStr> {
Cow::Borrowed($crate::jni_str!($class_name))
}
fn lookup_class<'caller>(
env: &Env<'_>,
loader_context: &LoaderContext,
) -> crate::errors::Result<impl Deref<Target = Global<JClass<'static>>> + 'caller> {
let api = $api_type::get(env, &loader_context)?;
Ok(&api.class)
}
unsafe fn kind_from_raw<'env>(local_ref: jobject) -> Self::Kind<'env> {
JPrimitiveArray {
obj: unsafe { JObject::kind_from_raw(local_ref) },
_marker: PhantomData,
}
}
unsafe fn global_kind_from_raw(global_ref: jobject) -> Self::GlobalKind {
JPrimitiveArray {
obj: unsafe { JObject::global_kind_from_raw(global_ref) },
_marker: PhantomData,
}
}
}
};
}
impl_ref_for_jprimitive_array!(jboolean, "[Z", JPrimitiveArrayAPI_jboolean);
impl_ref_for_jprimitive_array!(jbyte, "[B", JPrimitiveArrayAPI_jbyte);
impl_ref_for_jprimitive_array!(jchar, "[C", JPrimitiveArrayAPI_jchar);
impl_ref_for_jprimitive_array!(jshort, "[S", JPrimitiveArrayAPI_jshort);
impl_ref_for_jprimitive_array!(jint, "[I", JPrimitiveArrayAPI_jint);
impl_ref_for_jprimitive_array!(jlong, "[J", JPrimitiveArrayAPI_jlong);
impl_ref_for_jprimitive_array!(jfloat, "[F", JPrimitiveArrayAPI_jfloat);
impl_ref_for_jprimitive_array!(jdouble, "[D", JPrimitiveArrayAPI_jdouble);