1use crate::{AsArg, Env, JniType, Local, Ref, ReferenceType, ThrowableType};
2use jni_sys::*;
3use std::{
4 ffi::{CStr, CString},
5 marker::PhantomData,
6 ops::{Bound, RangeBounds},
7 ptr::null_mut,
8};
9
10pub trait PrimitiveArray<T>: Sized + ReferenceType
28where
29 T: Clone + Default,
30{
31 fn new<'env>(env: Env<'env>, size: usize) -> Local<'env, Self>;
33
34 fn len(self: &Ref<'_, Self>) -> usize;
36
37 fn is_empty(self: &Ref<'_, Self>) -> bool {
39 self.len() == 0
40 }
41
42 fn get_region(self: &Ref<'_, Self>, start: usize, elements: &mut [T]);
46
47 fn set_region(self: &Ref<'_, Self>, start: usize, elements: &[T]);
51
52 fn new_from<'env>(env: Env<'env>, elements: &[T]) -> Local<'env, Self> {
54 let array = Self::new(env, elements.len());
55 array.set_region(0, elements);
56 array
57 }
58
59 fn get_region_as_vec(self: &Ref<'_, Self>, range: impl RangeBounds<usize>) -> Vec<T> {
64 let len = self.len();
65
66 let start = match range.start_bound() {
67 Bound::Unbounded => 0,
68 Bound::Included(n) => *n,
69 Bound::Excluded(n) => *n + 1,
70 };
71
72 let end = match range.end_bound() {
73 Bound::Unbounded => len,
74 Bound::Included(n) => *n + 1,
75 Bound::Excluded(n) => *n,
76 };
77
78 assert!(start <= end);
79 assert!(end <= len);
80 let vec_len = end - start;
81
82 let mut vec = Vec::new();
83 vec.resize(vec_len, Default::default());
84 self.get_region(start, &mut vec[..]);
85 vec
86 }
87
88 fn as_vec(self: &Ref<'_, Self>) -> Vec<T> {
90 self.get_region_as_vec(0..self.len())
91 }
92}
93
94macro_rules! primitive_array {
95 ($name:ident, $type_str:expr, $type:ident { $new_array:ident $set_region:ident $get_region:ident } ) => {
96 pub enum $name {}
98
99 unsafe impl ReferenceType for $name {}
100 unsafe impl JniType for $name {
101 fn static_with_jni_type<R>(callback: impl FnOnce(&CStr) -> R) -> R {
102 callback($type_str)
103 }
104 }
105
106 impl PrimitiveArray<$type> for $name {
107 fn new<'env>(env: Env<'env>, size: usize) -> Local<'env, Self> {
108 assert!(size <= i32::MAX as usize); let size = size as jsize;
110 let jnienv = env.as_raw();
111 unsafe {
112 let object = ((**jnienv).v1_2.$new_array)(jnienv, size);
113 let exception = ((**jnienv).v1_2.ExceptionOccurred)(jnienv);
114 assert!(exception.is_null()); Local::from_raw(env, object)
116 }
117 }
118
119 fn new_from<'env>(env: Env<'env>, elements: &[$type]) -> Local<'env, Self> {
120 let array = Self::new(env, elements.len());
121 let size = elements.len() as jsize;
122 let env = array.env().as_raw();
123 unsafe {
124 ((**env).v1_1.$set_region)(
125 env,
126 array.as_raw(),
127 0,
128 size,
129 elements.as_ptr() as *const _,
130 );
131 }
132 array
133 }
134
135 fn len(self: &Ref<'_, Self>) -> usize {
136 let env = self.env().as_raw();
137 unsafe { ((**env).v1_2.GetArrayLength)(env, self.as_raw()) as usize }
138 }
139
140 fn get_region(self: &Ref<'_, Self>, start: usize, elements: &mut [$type]) {
141 assert!(start <= i32::MAX as usize); assert!(elements.len() <= i32::MAX as usize); let self_len = self.len() as jsize;
144 let elements_len = elements.len() as jsize;
145
146 let start = start as jsize;
147 let end = start + elements_len;
148 assert!(start <= end);
149 assert!(end <= self_len);
150
151 let env = self.env().as_raw();
152 unsafe {
153 ((**env).v1_1.$get_region)(
154 env,
155 self.as_raw(),
156 start,
157 elements_len,
158 elements.as_mut_ptr() as *mut _,
159 )
160 };
161 }
162
163 fn set_region(self: &Ref<'_, Self>, start: usize, elements: &[$type]) {
164 assert!(start <= i32::MAX as usize); assert!(elements.len() <= i32::MAX as usize); let self_len = self.len() as jsize;
167 let elements_len = elements.len() as jsize;
168
169 let start = start as jsize;
170 let end = start + elements_len;
171 assert!(start <= end);
172 assert!(end <= self_len);
173
174 let env = self.env().as_raw();
175 unsafe {
176 ((**env).v1_1.$set_region)(
177 env,
178 self.as_raw(),
179 start,
180 elements_len,
181 elements.as_ptr() as *const _,
182 )
183 };
184 }
185 }
186 };
187}
188
189primitive_array! { BooleanArray, c"[Z", bool { NewBooleanArray SetBooleanArrayRegion GetBooleanArrayRegion } }
190primitive_array! { ByteArray, c"[B", jbyte { NewByteArray SetByteArrayRegion GetByteArrayRegion } }
191primitive_array! { CharArray, c"[C", jchar { NewCharArray SetCharArrayRegion GetCharArrayRegion } }
192primitive_array! { ShortArray, c"[S", jshort { NewShortArray SetShortArrayRegion GetShortArrayRegion } }
193primitive_array! { IntArray, c"[I", jint { NewIntArray SetIntArrayRegion GetIntArrayRegion } }
194primitive_array! { LongArray, c"[J", jlong { NewLongArray SetLongArrayRegion GetLongArrayRegion } }
195primitive_array! { FloatArray, c"[F", jfloat { NewFloatArray SetFloatArrayRegion GetFloatArrayRegion } }
196primitive_array! { DoubleArray, c"[D", jdouble { NewDoubleArray SetDoubleArrayRegion GetDoubleArrayRegion } }
197
198pub struct ObjectArray<T: ReferenceType, E: ThrowableType>(
205 core::convert::Infallible,
206 PhantomData<(T, E)>,
207);
208
209unsafe impl<T: ReferenceType, E: ThrowableType> ReferenceType for ObjectArray<T, E> {}
210
211unsafe impl<T: ReferenceType, E: ThrowableType> JniType for ObjectArray<T, E> {
212 fn static_with_jni_type<R>(callback: impl FnOnce(&CStr) -> R) -> R {
213 T::static_with_jni_type(|inner| {
214 let inner = inner.to_bytes();
215 let mut buf = Vec::with_capacity(inner.len() + 4);
216 buf.extend_from_slice(b"[L");
217 buf.extend_from_slice(inner);
218 buf.extend_from_slice(b";");
219 callback(&CString::new(buf).unwrap())
220 })
221 }
222}
223
224impl<T: ReferenceType, E: ThrowableType> ObjectArray<T, E> {
225 pub fn new<'env>(env: Env<'env>, size: usize) -> Local<'env, Self> {
227 assert!(size <= i32::MAX as usize); let class = T::static_with_jni_type(|t| unsafe { env.require_class(t) });
229 let size = size as jsize;
230
231 let object = unsafe {
232 let env = env.as_raw();
233 let fill = null_mut();
234 ((**env).v1_2.NewObjectArray)(env, size, class, fill)
235 };
236 env.exception_check::<E>().map_err(|_| "OOM").unwrap();
238
239 unsafe {
240 let env = env.as_raw();
241 ((**env).v1_2.DeleteLocalRef)(env, class);
242 }
243 unsafe { Local::from_raw(env, object) }
244 }
245
246 pub fn iter<'a, 'env>(self: &'a Ref<'env, Self>) -> ObjectArrayIter<'a, 'env, T, E> {
248 ObjectArrayIter {
249 array: self,
250 index: 0,
251 length: self.len(),
252 }
253 }
254
255 pub fn new_from<'env>(
258 env: Env<'env>,
259 elements: impl ExactSizeIterator<Item = impl AsArg<T>>,
260 ) -> Local<'env, Self> {
261 let size = elements.len();
262 let array = Self::new(env, size);
263 let env = array.env().as_raw();
264 for (index, element) in elements.enumerate() {
265 assert!(index < size); unsafe {
267 ((**env).v1_2.SetObjectArrayElement)(
268 env,
269 array.as_raw(),
270 index as jsize,
271 element.as_arg(),
272 )
273 };
274 }
275 array
276 }
277
278 pub fn len(self: &Ref<'_, Self>) -> usize {
280 let env = self.env().as_raw();
281 unsafe { ((**env).v1_2.GetArrayLength)(env, self.as_raw()) as usize }
282 }
283
284 pub fn get<'env>(
289 self: &Ref<'env, Self>,
290 index: usize,
291 ) -> Result<Option<Local<'env, T>>, Local<'env, E>> {
292 assert!(index <= i32::MAX as usize); let index = index as jsize;
294 let env = self.env();
295 let result = unsafe {
296 let env = env.as_raw();
297 ((**env).v1_2.GetObjectArrayElement)(env, self.as_raw(), index)
298 };
299 env.exception_check()?;
300 if result.is_null() {
301 Ok(None)
302 } else {
303 Ok(Some(unsafe { Local::from_raw(env, result) }))
304 }
305 }
306
307 pub fn set<'env>(
311 self: &Ref<'env, Self>,
312 index: usize,
313 value: impl AsArg<T>,
314 ) -> Result<(), Local<'env, E>> {
315 assert!(index <= i32::MAX as usize); let index = index as jsize;
317 let env = self.env();
318 unsafe {
319 let env = env.as_raw();
320 ((**env).v1_2.SetObjectArrayElement)(env, self.as_raw(), index, value.as_arg());
321 }
322 env.exception_check()
323 }
324}
325
326pub struct ObjectArrayIter<'a, 'env, T: ReferenceType, E: ThrowableType> {
329 array: &'a Ref<'env, ObjectArray<T, E>>,
330 index: usize,
331 length: usize,
332}
333
334impl<'a, 'env, T: ReferenceType, E: ThrowableType> Iterator for ObjectArrayIter<'a, 'env, T, E> {
335 type Item = Option<Local<'env, T>>;
336 fn next(&mut self) -> Option<Self::Item> {
337 let index = self.index;
338 if index < self.length {
339 self.index = index + 1;
340 Some(self.array.get(index).unwrap_or(None))
341 } else {
342 None
343 }
344 }
345}