1 use log::error; 2 use std::ptr::NonNull; 3 4 use crate::sys::jboolean; 5 use crate::wrapper::objects::ReleaseMode; 6 use crate::{errors::*, sys, JNIEnv}; 7 8 use super::{JPrimitiveArray, TypeArray}; 9 10 #[cfg(doc)] 11 use super::JByteArray; 12 13 /// Auto-release wrapper for a mutable pointer to the elements of a [`JPrimitiveArray`] 14 /// (such as [`JByteArray`]) 15 /// 16 /// This type is used to wrap pointers returned by `GetPrimitiveArrayCritical` 17 /// and ensure the pointer is released via `ReleasePrimitiveArrayCritical` when dropped. 18 pub struct AutoElementsCritical<'local, 'other_local, 'array, 'env, T: TypeArray> { 19 array: &'array JPrimitiveArray<'other_local, T>, 20 len: usize, 21 ptr: NonNull<T>, 22 mode: ReleaseMode, 23 is_copy: bool, 24 env: &'env mut JNIEnv<'local>, 25 } 26 27 impl<'local, 'other_local, 'array, 'env, T: TypeArray> 28 AutoElementsCritical<'local, 'other_local, 'array, 'env, T> 29 { 30 /// # Safety 31 /// 32 /// `len` must be the correct length (number of elements) of the given `array` new_with_len( env: &'env mut JNIEnv<'local>, array: &'array JPrimitiveArray<'other_local, T>, len: usize, mode: ReleaseMode, ) -> Result<Self>33 pub(crate) unsafe fn new_with_len( 34 env: &'env mut JNIEnv<'local>, 35 array: &'array JPrimitiveArray<'other_local, T>, 36 len: usize, 37 mode: ReleaseMode, 38 ) -> Result<Self> { 39 let mut is_copy: jboolean = 0xff; 40 // Even though this method may throw OoME, use `jni_unchecked` 41 // instead of `jni_non_null_call` to remove (a slight) overhead 42 // of exception checking. An error will still be detected as a `null` 43 // result below; and, as this method is unlikely to create a copy, 44 // an OoME is highly unlikely. 45 let ptr = jni_unchecked!( 46 env.get_native_interface(), 47 GetPrimitiveArrayCritical, 48 array.as_raw(), 49 &mut is_copy 50 ) as *mut T; 51 52 Ok(AutoElementsCritical { 53 array, 54 len, 55 ptr: NonNull::new(ptr).ok_or(Error::NullPtr("Non-null ptr expected"))?, 56 mode, 57 is_copy: is_copy == sys::JNI_TRUE, 58 env, 59 }) 60 } 61 new( env: &'env mut JNIEnv<'local>, array: &'array JPrimitiveArray<'other_local, T>, mode: ReleaseMode, ) -> Result<Self>62 pub(crate) fn new( 63 env: &'env mut JNIEnv<'local>, 64 array: &'array JPrimitiveArray<'other_local, T>, 65 mode: ReleaseMode, 66 ) -> Result<Self> { 67 let len = env.get_array_length(array)? as usize; 68 unsafe { Self::new_with_len(env, array, len, mode) } 69 } 70 71 /// Get a reference to the wrapped pointer as_ptr(&self) -> *mut T72 pub fn as_ptr(&self) -> *mut T { 73 self.ptr.as_ptr() 74 } 75 76 /// Calls `ReleasePrimitiveArrayCritical`. 77 /// 78 /// # Safety 79 /// 80 /// `mode` must be a valid parameter to the JNI `ReleasePrimitiveArrayCritical` `mode` 81 /// parameter. 82 /// 83 /// If `mode` is not [`sys::JNI_COMMIT`], then `self.ptr` must not have already been released. release_primitive_array_critical(&mut self, mode: i32) -> Result<()>84 unsafe fn release_primitive_array_critical(&mut self, mode: i32) -> Result<()> { 85 jni_unchecked!( 86 self.env.get_native_interface(), 87 ReleasePrimitiveArrayCritical, 88 self.array.as_raw(), 89 self.ptr.as_ptr().cast(), 90 mode 91 ); 92 Ok(()) 93 } 94 95 /// Don't copy back the changes to the array on release (if it is a copy). 96 /// 97 /// This has no effect if the array is not a copy. 98 /// 99 /// This method is useful to change the release mode of an array originally created 100 /// with `ReleaseMode::CopyBack`. discard(&mut self)101 pub fn discard(&mut self) { 102 self.mode = ReleaseMode::NoCopyBack; 103 } 104 105 /// Indicates if the array is a copy or not is_copy(&self) -> bool106 pub fn is_copy(&self) -> bool { 107 self.is_copy 108 } 109 110 /// Returns the array length (number of elements) len(&self) -> usize111 pub fn len(&self) -> usize { 112 self.len 113 } 114 115 /// Returns true if the vector contains no elements. is_empty(&self) -> bool116 pub fn is_empty(&self) -> bool { 117 self.len == 0 118 } 119 } 120 121 impl<'local, 'other_local, 'array, 'env, T: TypeArray> 122 AsRef<AutoElementsCritical<'local, 'other_local, 'array, 'env, T>> 123 for AutoElementsCritical<'local, 'other_local, 'array, 'env, T> 124 { as_ref(&self) -> &AutoElementsCritical<'local, 'other_local, 'array, 'env, T>125 fn as_ref(&self) -> &AutoElementsCritical<'local, 'other_local, 'array, 'env, T> { 126 self 127 } 128 } 129 130 impl<'local, 'other_local, 'array, 'env, T: TypeArray> Drop 131 for AutoElementsCritical<'local, 'other_local, 'array, 'env, T> 132 { drop(&mut self)133 fn drop(&mut self) { 134 // Safety: `self.mode` is valid and the array has not yet been released. 135 let res = unsafe { self.release_primitive_array_critical(self.mode as i32) }; 136 137 match res { 138 Ok(()) => {} 139 Err(e) => error!("error releasing primitive array: {:#?}", e), 140 } 141 } 142 } 143 144 impl<'local, 'other_local, 'array, 'env, T: TypeArray> 145 From<&AutoElementsCritical<'local, 'other_local, 'array, 'env, T>> for *mut T 146 { from(other: &AutoElementsCritical<T>) -> *mut T147 fn from(other: &AutoElementsCritical<T>) -> *mut T { 148 other.as_ptr() 149 } 150 } 151 152 impl<'local, 'other_local, 'array, 'env, T: TypeArray> std::ops::Deref 153 for AutoElementsCritical<'local, 'other_local, 'array, 'env, T> 154 { 155 type Target = [T]; 156 deref(&self) -> &Self::Target157 fn deref(&self) -> &Self::Target { 158 unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) } 159 } 160 } 161 162 impl<'local, 'other_local, 'array, 'env, T: TypeArray> std::ops::DerefMut 163 for AutoElementsCritical<'local, 'other_local, 'array, 'env, T> 164 { deref_mut(&mut self) -> &mut Self::Target165 fn deref_mut(&mut self) -> &mut Self::Target { 166 unsafe { std::slice::from_raw_parts_mut(self.ptr.as_mut(), self.len) } 167 } 168 } 169