1use std::marker::PhantomData;
2use std::ops::{Bound, RangeBounds};
3use std::ptr::null_mut;
4
5use jni_sys::*;
6
7use crate::{AsArg, Env, JniType, Local, ObjectAndEnv, ReferenceType, ThrowableType};
8
9pub trait PrimitiveArray<T>: Sized + ReferenceType
24where
25 T: Clone + Default,
26{
27 fn new<'env>(env: Env<'env>, size: usize) -> Local<'env, Self>;
29
30 fn len(&self) -> usize;
32
33 fn get_region(&self, start: usize, elements: &mut [T]);
35
36 fn set_region(&self, start: usize, elements: &[T]);
38
39 fn new_from<'env>(env: Env<'env>, elements: &[T]) -> Local<'env, Self> {
41 let array = Self::new(env, elements.len());
42 array.set_region(0, elements);
43 array
44 }
45
46 fn get_region_as_vec(&self, range: impl RangeBounds<usize>) -> Vec<T> {
48 let len = self.len();
49
50 let start = match range.start_bound() {
51 Bound::Unbounded => 0,
52 Bound::Included(n) => *n,
53 Bound::Excluded(n) => *n + 1,
54 };
55
56 let end = match range.end_bound() {
57 Bound::Unbounded => len,
58 Bound::Included(n) => *n + 1,
59 Bound::Excluded(n) => *n,
60 };
61
62 assert!(start <= end);
63 assert!(end <= len);
64 let vec_len = end - start;
65
66 let mut vec = Vec::new();
67 vec.resize(vec_len, Default::default());
68 self.get_region(start, &mut vec[..]);
69 vec
70 }
71
72 fn as_vec(&self) -> Vec<T> {
74 self.get_region_as_vec(0..self.len())
75 }
76}
77
78macro_rules! primitive_array {
79 (#[repr(transparent)] pub struct $name:ident = $type_str:expr, $type:ident { $new_array:ident $set_region:ident $get_region:ident } ) => {
80 #[repr(transparent)]
82 pub struct $name(ObjectAndEnv);
83
84 unsafe impl ReferenceType for $name {}
85 unsafe impl JniType for $name {
86 fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
87 callback($type_str)
88 }
89 }
90
91 impl PrimitiveArray<$type> for $name {
92 fn new<'env>(env: Env<'env>, size: usize) -> Local<'env, Self> {
93 assert!(size <= std::i32::MAX as usize); let size = size as jsize;
95 let jnienv = env.as_raw();
96 unsafe {
97 let object = ((**jnienv).v1_2.$new_array)(jnienv, size);
98 let exception = ((**jnienv).v1_2.ExceptionOccurred)(jnienv);
99 assert!(exception.is_null()); Local::from_raw(env, object)
101 }
102 }
103
104 fn new_from<'env>(env: Env<'env>, elements: &[$type]) -> Local<'env, Self> {
105 let array = Self::new(env, elements.len());
106 let size = elements.len() as jsize;
107 let env = array.0.env;
108 let object = array.0.object;
109 unsafe {
110 ((**env).v1_1.$set_region)(env, object, 0, size, elements.as_ptr() as *const _);
111 }
112 array
113 }
114
115 fn len(&self) -> usize {
116 unsafe { ((**self.0.env).v1_2.GetArrayLength)(self.0.env as *mut _, self.0.object) as usize }
117 }
118
119 fn get_region(&self, start: usize, elements: &mut [$type]) {
120 assert!(start <= std::i32::MAX as usize); assert!(elements.len() <= std::i32::MAX as usize); let self_len = self.len() as jsize;
123 let elements_len = elements.len() as jsize;
124
125 let start = start as jsize;
126 let end = start + elements_len;
127 assert!(start <= end);
128 assert!(end <= self_len);
129
130 unsafe {
131 ((**self.0.env).v1_1.$get_region)(
132 self.0.env as *mut _,
133 self.0.object,
134 start,
135 elements_len,
136 elements.as_mut_ptr() as *mut _,
137 )
138 };
139 }
140
141 fn set_region(&self, start: usize, elements: &[$type]) {
142 assert!(start <= std::i32::MAX as usize); assert!(elements.len() <= std::i32::MAX as usize); let self_len = self.len() as jsize;
145 let elements_len = elements.len() as jsize;
146
147 let start = start as jsize;
148 let end = start + elements_len;
149 assert!(start <= end);
150 assert!(end <= self_len);
151
152 unsafe {
153 ((**self.0.env).v1_1.$set_region)(
154 self.0.env as *mut _,
155 self.0.object,
156 start,
157 elements_len,
158 elements.as_ptr() as *const _,
159 )
160 };
161 }
162 }
163 };
164}
165
166primitive_array! { #[repr(transparent)] pub struct BooleanArray = "[Z\0", bool { NewBooleanArray SetBooleanArrayRegion GetBooleanArrayRegion } }
167primitive_array! { #[repr(transparent)] pub struct ByteArray = "[B\0", jbyte { NewByteArray SetByteArrayRegion GetByteArrayRegion } }
168primitive_array! { #[repr(transparent)] pub struct CharArray = "[C\0", jchar { NewCharArray SetCharArrayRegion GetCharArrayRegion } }
169primitive_array! { #[repr(transparent)] pub struct ShortArray = "[S\0", jshort { NewShortArray SetShortArrayRegion GetShortArrayRegion } }
170primitive_array! { #[repr(transparent)] pub struct IntArray = "[I\0", jint { NewIntArray SetIntArrayRegion GetIntArrayRegion } }
171primitive_array! { #[repr(transparent)] pub struct LongArray = "[J\0", jlong { NewLongArray SetLongArrayRegion GetLongArrayRegion } }
172primitive_array! { #[repr(transparent)] pub struct FloatArray = "[F\0", jfloat { NewFloatArray SetFloatArrayRegion GetFloatArrayRegion } }
173primitive_array! { #[repr(transparent)] pub struct DoubleArray = "[D\0", jdouble { NewDoubleArray SetDoubleArrayRegion GetDoubleArrayRegion } }
174
175#[repr(transparent)]
179pub struct ObjectArray<T: ReferenceType, E: ThrowableType>(ObjectAndEnv, PhantomData<(T, E)>);
180
181unsafe impl<T: ReferenceType, E: ThrowableType> ReferenceType for ObjectArray<T, E> {}
182
183unsafe impl<T: ReferenceType, E: ThrowableType> JniType for ObjectArray<T, E> {
184 fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
185 T::static_with_jni_type(|inner| callback(format!("[{}", inner).as_str()))
186 }
187}
188
189impl<T: ReferenceType, E: ThrowableType> ObjectArray<T, E> {
190 pub fn new<'env>(env: Env<'env>, size: usize) -> Local<'env, Self> {
191 assert!(size <= std::i32::MAX as usize); let class = Self::static_with_jni_type(|t| unsafe { env.require_class(t) });
193 let size = size as jsize;
194 let jnienv = env.as_raw();
195 unsafe {
196 let fill = null_mut();
197 let object = ((**jnienv).v1_2.NewObjectArray)(jnienv, size, class, fill);
198 let exception = ((**jnienv).v1_2.ExceptionOccurred)(jnienv);
199 assert!(exception.is_null()); Local::from_raw(env, object)
201 }
202 }
203
204 pub fn iter(&self) -> ObjectArrayIter<'_, T, E> {
205 ObjectArrayIter {
206 array: self,
207 index: 0,
208 length: self.len(),
209 }
210 }
211
212 pub fn new_from<'env>(
213 env: Env<'env>,
214 elements: impl ExactSizeIterator + Iterator<Item = impl AsArg<T>>,
215 ) -> Local<'env, Self> {
216 let size = elements.len();
217 let array = Self::new(env, size);
218 let env = array.0.env;
219 let this = array.0.object;
220
221 for (index, element) in elements.enumerate() {
222 assert!(index < size); unsafe { ((**env).v1_2.SetObjectArrayElement)(env, this, index as jsize, element.as_arg()) };
224 }
225 array
226 }
227
228 pub fn len(&self) -> usize {
229 unsafe { ((**self.0.env).v1_2.GetArrayLength)(self.0.env as *mut _, self.0.object) as usize }
230 }
231
232 pub fn get(&self, index: usize) -> Result<Option<Local<'_, T>>, Local<'_, E>> {
234 assert!(index <= std::i32::MAX as usize); let index = index as jsize;
236 let env = self.0.env;
237 let this = self.0.object;
238 unsafe {
239 let result = ((**env).v1_2.GetObjectArrayElement)(env, this, index);
240 let exception = ((**env).v1_2.ExceptionOccurred)(env);
241 if !exception.is_null() {
242 ((**env).v1_2.ExceptionClear)(env);
243 Err(Local::from_raw(Env::from_raw(env), exception))
244 } else if result.is_null() {
245 Ok(None)
246 } else {
247 Ok(Some(Local::from_raw(Env::from_raw(env), result)))
248 }
249 }
250 }
251
252 pub fn set<'env>(&'env self, index: usize, value: impl AsArg<T>) -> Result<(), Local<'env, E>> {
254 assert!(index <= std::i32::MAX as usize); let index = index as jsize;
256 let env = self.0.env;
257 let this = self.0.object;
258 unsafe {
259 ((**env).v1_2.SetObjectArrayElement)(env, this, index, value.as_arg());
260 let exception = ((**env).v1_2.ExceptionOccurred)(env);
261 if !exception.is_null() {
262 ((**env).v1_2.ExceptionClear)(env);
263 Err(Local::from_raw(Env::from_raw(env), exception))
264 } else {
265 Ok(())
266 }
267 }
268 }
269}
270
271pub struct ObjectArrayIter<'env, T: ReferenceType, E: ThrowableType> {
272 array: &'env ObjectArray<T, E>,
273 index: usize,
274 length: usize,
275}
276
277impl<'env, T: ReferenceType, E: ThrowableType> Iterator for ObjectArrayIter<'env, T, E> {
278 type Item = Option<Local<'env, T>>;
279 fn next(&mut self) -> Option<Self::Item> {
280 let index = self.index;
281 if index < self.length {
282 self.index = index + 1;
283 Some(self.array.get(index).unwrap_or(None))
284 } else {
285 None
286 }
287 }
288}