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