java_spaghetti/
array.rs

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
9/// A Java Array of some POD-like type such as bool, jbyte, jchar, jshort, jint, jlong, jfloat, or jdouble.
10///
11/// See also [ObjectArray] for arrays of reference types.
12///
13/// | JNI Type      | PrimitiveArray Implementation |
14/// | ------------- | ----------------- |
15/// | [bool]\[\]    | [BooleanArray]    |
16/// | [jbyte]\[\]   | [ByteArray]       |
17/// | [jchar]\[\]   | [CharArray]       |
18/// | [jint]\[\]    | [IntArray]        |
19/// | [jlong]\[\]   | [LongArray]       |
20/// | [jfloat]\[\]  | [FloatArray]      |
21/// | [jdouble]\[\] | [DoubleArray]     |
22///
23pub trait PrimitiveArray<T>: Sized + ReferenceType
24where
25    T: Clone + Default,
26{
27    /// Uses env.New{Type}Array to create a new java array containing "size" elements.
28    fn new<'env>(env: Env<'env>, size: usize) -> Local<'env, Self>;
29
30    /// Uses env.GetArrayLength to get the length of the java array.
31    fn len(&self) -> usize;
32
33    /// Uses env.Get{Type}ArrayRegion to read the contents of the java array from \[start .. start + elements.len())
34    fn get_region(&self, start: usize, elements: &mut [T]);
35
36    /// Uses env.Set{Type}ArrayRegion to set the contents of the java array from \[start .. start + elements.len())
37    fn set_region(&self, start: usize, elements: &[T]);
38
39    /// Uses env.New{Type}Array + Set{Type}ArrayRegion to create a new java array containing a copy of "elements".
40    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    /// Uses env.GetArrayLength + env.Get{Type}ArrayRegion to read the contents of the java array from range into a new Vec.
47    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    /// Uses env.GetArrayLength + env.Get{Type}ArrayRegion to read the contents of the entire java array into a new Vec.
73    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        /// A [PrimitiveArray] implementation.
81        #[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); // jsize == jint == i32
94                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()); // Only sane exception here is an OOM exception
100                    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); // jsize == jint == i32
121                assert!(elements.len() <= std::i32::MAX as usize); // jsize == jint == i32
122                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); // jsize == jint == i32
143                assert!(elements.len() <= std::i32::MAX as usize); // jsize == jint == i32
144                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/// A Java Array of reference types (classes, interfaces, other arrays, etc.)
176///
177/// See also [PrimitiveArray] for arrays of reference types.
178#[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); // jsize == jint == i32
192        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()); // Only sane exception here is an OOM exception
200            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); // Should only be violated by an invalid ExactSizeIterator implementation.
223            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    /// XXX: Expose this via std::ops::Index
233    pub fn get(&self, index: usize) -> Result<Option<Local<'_, T>>, Local<'_, E>> {
234        assert!(index <= std::i32::MAX as usize); // jsize == jint == i32 XXX: Should maybe be treated as an exception?
235        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    /// XXX: I don't think there's a way to expose this via std::ops::IndexMut sadly?
253    pub fn set<'env>(&'env self, index: usize, value: impl AsArg<T>) -> Result<(), Local<'env, E>> {
254        assert!(index <= std::i32::MAX as usize); // jsize == jint == i32 XXX: Should maybe be treated as an exception?
255        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}