use log::error;
use std::marker::PhantomData;
use std::ptr::NonNull;
use crate::objects::{JPrimitiveArray, Reference, ReleaseMode, TypeArray};
use crate::sys::jboolean;
use crate::{JavaVM, env::Env, errors::*, sys};
#[cfg(doc)]
use crate::objects::JByteArray;
#[derive(Debug)]
pub struct AutoElements<'array_local, T, TArrayRef>
where
T: TypeArray + 'array_local,
TArrayRef: AsRef<JPrimitiveArray<'array_local, T>>,
{
array: TArrayRef,
len: usize,
ptr: NonNull<T>,
mode: ReleaseMode,
is_copy: bool,
_lifetime: PhantomData<&'array_local ()>,
}
impl<'array_local, T, TArrayRef> AutoElements<'array_local, T, TArrayRef>
where
T: TypeArray + 'array_local,
TArrayRef: AsRef<JPrimitiveArray<'array_local, T>>,
{
unsafe fn new_with_len(
env: &Env<'_>,
array: TArrayRef,
len: usize,
mode: ReleaseMode,
) -> Result<Self> {
let mut is_copy: jboolean = true;
let ptr = unsafe { T::get_elements(env, array.as_ref().as_raw(), &mut is_copy) }?;
Ok(AutoElements {
array,
len,
ptr: NonNull::new(ptr).ok_or(Error::NullPtr("Non-null ptr expected"))?,
mode,
is_copy: is_copy == sys::JNI_TRUE,
_lifetime: PhantomData,
})
}
pub(crate) fn new(env: &Env<'_>, array: TArrayRef, mode: ReleaseMode) -> Result<Self> {
let len = array.as_ref().len(env)?;
unsafe { Self::new_with_len(env, array, len, mode) }
}
pub fn as_ptr(&self) -> *mut T {
self.ptr.as_ptr()
}
pub fn commit(&mut self) -> Result<()> {
unsafe { self.release_array_elements(sys::JNI_COMMIT) }
}
unsafe fn release_array_elements(&self, mode: i32) -> Result<()> {
JavaVM::singleton()?.with_top_local_frame(|env| unsafe {
T::release_elements(env, self.array.as_ref().as_raw(), self.ptr, mode)
})
}
pub fn discard(mut self) {
self.mode = ReleaseMode::NoCopyBack;
}
pub fn is_copy(&self) -> bool {
self.is_copy
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
impl<'array_local, T, TArrayRef> AsRef<AutoElements<'array_local, T, TArrayRef>>
for AutoElements<'array_local, T, TArrayRef>
where
T: TypeArray + 'array_local,
TArrayRef: AsRef<JPrimitiveArray<'array_local, T>> + Reference,
{
fn as_ref(&self) -> &AutoElements<'array_local, T, TArrayRef> {
self
}
}
impl<'array_local, T, TArrayRef> Drop for AutoElements<'array_local, T, TArrayRef>
where
T: TypeArray,
TArrayRef: AsRef<JPrimitiveArray<'array_local, T>>,
{
fn drop(&mut self) {
let res = unsafe { self.release_array_elements(self.mode as i32) };
match res {
Ok(()) => {}
Err(e) => error!("error releasing array: {:#?}", e),
}
}
}
impl<'array_local, T, TArrayRef> From<&AutoElements<'array_local, T, TArrayRef>> for *mut T
where
T: TypeArray,
TArrayRef: AsRef<JPrimitiveArray<'array_local, T>> + Reference,
{
fn from(other: &AutoElements<'array_local, T, TArrayRef>) -> *mut T {
other.as_ptr()
}
}
impl<'array_local, T, TArrayRef> std::ops::Deref for AutoElements<'array_local, T, TArrayRef>
where
T: TypeArray,
TArrayRef: AsRef<JPrimitiveArray<'array_local, T>> + Reference,
{
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
}
impl<'array_local, T, TArrayRef> std::ops::DerefMut for AutoElements<'array_local, T, TArrayRef>
where
T: TypeArray,
TArrayRef: AsRef<JPrimitiveArray<'array_local, T>> + Reference,
{
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { std::slice::from_raw_parts_mut(self.ptr.as_mut(), self.len) }
}
}