1
+ use std:: borrow:: Cow ;
1
2
use std:: collections:: HashMap ;
2
3
use std:: marker:: PhantomData ;
3
4
use std:: ops:: { Bound , RangeBounds } ;
@@ -6,12 +7,12 @@ use std::sync::{LazyLock, OnceLock, RwLock};
6
7
7
8
use jni_sys:: * ;
8
9
9
- use crate :: { AsArg , Env , JClass , JniType , Local , Ref , ReferenceType , ThrowableType } ;
10
+ use crate :: { AsArg , Env , JClass , Local , Ref , ReferenceType , ThrowableType } ;
10
11
11
12
/// A Java Array of some POD-like type such as `bool`, `jbyte`, `jchar`, `jshort`, `jint`, `jlong`, `jfloat`, or `jdouble`.
12
13
///
13
14
/// Thread safety of avoiding [race conditions](https://www.ibm.com/docs/en/sdk-java-technology/8?topic=jni-synchronization)
14
- /// is not guaranteed.
15
+ /// is not guaranteed. JNI `GetPrimitiveArrayCritical` cannot ensure exclusive access to the array, so it is not used here.
15
16
///
16
17
/// See also [ObjectArray] for arrays of reference types.
17
18
///
@@ -29,35 +30,35 @@ pub trait PrimitiveArray<T>: Sized + ReferenceType
29
30
where
30
31
T : Clone + Default ,
31
32
{
32
- /// Uses JNI `New{Type}Array` to create a new java array containing "size" elements.
33
+ /// Uses JNI `New{Type}Array` to create a new Java array containing "size" elements.
33
34
fn new < ' env > ( env : Env < ' env > , size : usize ) -> Local < ' env , Self > ;
34
35
35
- /// Uses JNI `GetArrayLength` to get the length of the java array.
36
+ /// Uses JNI `GetArrayLength` to get the length of the Java array.
36
37
fn len ( self : & Ref < ' _ , Self > ) -> usize ;
37
38
38
- /// Uses JNI `Get{Type}ArrayRegion` to read the contents of the java array within `[start .. start + elements.len()]`.
39
+ /// Uses JNI `Get{Type}ArrayRegion` to read the contents of the Java array within `[start .. start + elements.len()]`.
39
40
///
40
41
/// Panics if the index is out of bound.
41
42
fn get_region ( self : & Ref < ' _ , Self > , start : usize , elements : & mut [ T ] ) ;
42
43
43
- /// Uses JNI `Set{Type}ArrayRegion` to set the contents of the java array within `[start .. start + elements.len()]`.
44
+ /// Uses JNI `Set{Type}ArrayRegion` to set the contents of the Java array within `[start .. start + elements.len()]`.
44
45
///
45
46
/// Panics if the index is out of bound.
46
47
fn set_region ( self : & Ref < ' _ , Self > , start : usize , elements : & [ T ] ) ;
47
48
48
- /// Uses JNI `New{Type}Array` + `Set{Type}ArrayRegion` to create a new java array containing a copy of "elements".
49
+ /// Uses JNI `New{Type}Array` + `Set{Type}ArrayRegion` to create a new Java array containing a copy of "elements".
49
50
fn new_from < ' env > ( env : Env < ' env > , elements : & [ T ] ) -> Local < ' env , Self > {
50
51
let array = Self :: new ( env, elements. len ( ) ) ;
51
52
array. set_region ( 0 , elements) ;
52
53
array
53
54
}
54
55
55
- /// Uses JNI `GetArrayLength` to get the length of the java array, returns `true` if it is 0.
56
+ /// Uses JNI `GetArrayLength` to get the length of the Java array, returns `true` if it is 0.
56
57
fn is_empty ( self : & Ref < ' _ , Self > ) -> bool {
57
58
self . len ( ) == 0
58
59
}
59
60
60
- /// Uses JNI `GetArrayLength` + `Get{Type}ArrayRegion` to read the contents of the java array within given range
61
+ /// Uses JNI `GetArrayLength` + `Get{Type}ArrayRegion` to read the contents of the Java array within given range
61
62
/// into a new `Vec`.
62
63
///
63
64
/// Panics if the index is out of bound.
86
87
vec
87
88
}
88
89
89
- /// Uses JNI `GetArrayLength` + `Get{Type}ArrayRegion` to read the contents of the entire java array into a new `Vec`.
90
+ /// Uses JNI `GetArrayLength` + `Get{Type}ArrayRegion` to read the contents of the entire Java array into a new `Vec`.
90
91
fn as_vec ( self : & Ref < ' _ , Self > ) -> Vec < T > {
91
92
self . get_region_as_vec ( 0 ..self . len ( ) )
92
93
}
@@ -98,14 +99,12 @@ macro_rules! primitive_array {
98
99
pub enum $name { }
99
100
100
101
unsafe impl ReferenceType for $name {
102
+ fn jni_reference_type_name( ) -> Cow <' static , str > {
103
+ Cow :: Borrowed ( $type_str)
104
+ }
101
105
fn jni_get_class( env: Env ) -> & ' static JClass {
102
106
static CLASS_CACHE : OnceLock <JClass > = OnceLock :: new( ) ;
103
- CLASS_CACHE . get_or_init( || Self :: static_with_jni_type( |t| unsafe { env. require_class( t) } ) )
104
- }
105
- }
106
- unsafe impl JniType for $name {
107
- fn static_with_jni_type<R >( callback: impl FnOnce ( & str ) -> R ) -> R {
108
- callback( $type_str)
107
+ CLASS_CACHE . get_or_init( || unsafe { env. require_class( & Self :: jni_reference_type_name( ) ) } )
109
108
}
110
109
}
111
110
@@ -116,8 +115,8 @@ macro_rules! primitive_array {
116
115
let jnienv = env. as_raw( ) ;
117
116
unsafe {
118
117
let object = ( ( * * jnienv) . v1_2. $new_array) ( jnienv, size) ;
119
- let exception = ( ( * * jnienv ) . v1_2 . ExceptionOccurred ) ( jnienv ) ;
120
- assert! ( exception . is_null ( ) ) ; // Only sane exception here is an OOM exception
118
+ assert! ( !object . is_null ( ) , "OOM" ) ;
119
+ env . exception_check_raw ( ) . expect ( "OOM" ) ; // Only sane exception here is an OOM exception
121
120
Local :: from_raw( env, object)
122
121
}
123
122
}
@@ -203,35 +202,32 @@ primitive_array! { DoubleArray, "[D\0", jdouble { NewDoubleArray SetDoubleArra
203
202
/// See also [PrimitiveArray] for arrays of reference types.
204
203
pub struct ObjectArray < T : ReferenceType , E : ThrowableType > ( core:: convert:: Infallible , PhantomData < ( T , E ) > ) ;
205
204
206
- // NOTE: This is a performance compromise for returning `&'static JClass`,
207
- // still faster than non-cached `require_class`.
205
+ // NOTE: This is a performance compromise for returning `&'static JClass`, still faster than non-cached `FindClass`.
208
206
static OBJ_ARR_CLASSES : LazyLock < RwLock < HashMap < String , & ' static JClass > > > =
209
207
LazyLock :: new ( || RwLock :: new ( HashMap :: new ( ) ) ) ;
210
208
211
209
unsafe impl < T : ReferenceType , E : ThrowableType > ReferenceType for ObjectArray < T , E > {
212
- fn jni_get_class ( env : Env ) -> & ' static JClass {
213
- Self :: static_with_jni_type ( |t| {
214
- let class_map_reader = OBJ_ARR_CLASSES . read ( ) . unwrap ( ) ;
215
- if let Some ( & class) = class_map_reader. get ( t) {
216
- class
217
- } else {
218
- drop ( class_map_reader) ;
219
- let class: & ' static JClass = Box :: leak ( Box :: new ( unsafe { env. require_class ( t) } ) ) ;
220
- let _ = OBJ_ARR_CLASSES . write ( ) . unwrap ( ) . insert ( t. to_string ( ) , class) ;
221
- class
222
- }
223
- } )
210
+ fn jni_reference_type_name ( ) -> Cow < ' static , str > {
211
+ let inner = T :: jni_reference_type_name ( ) ;
212
+ Cow :: Owned ( format ! ( "[L{};\0 " , inner. trim_end_matches( "\0 " ) ) )
224
213
}
225
- }
226
-
227
- unsafe impl < T : ReferenceType , E : ThrowableType > JniType for ObjectArray < T , E > {
228
- fn static_with_jni_type < R > ( callback : impl FnOnce ( & str ) -> R ) -> R {
229
- T :: static_with_jni_type ( |inner| callback ( format ! ( "[L{};\0 " , inner. trim_end_matches( "\0 " ) ) . as_str ( ) ) )
214
+ fn jni_get_class ( env : Env ) -> & ' static JClass {
215
+ let t = Self :: jni_reference_type_name ( ) ;
216
+ let class_map_reader = OBJ_ARR_CLASSES . read ( ) . unwrap ( ) ;
217
+ if let Some ( & class) = class_map_reader. get ( t. as_ref ( ) ) {
218
+ class
219
+ } else {
220
+ drop ( class_map_reader) ;
221
+ let class = unsafe { env. require_class ( & t) } ;
222
+ let class_leaked: & ' static JClass = Box :: leak ( Box :: new ( class) ) ;
223
+ let _ = OBJ_ARR_CLASSES . write ( ) . unwrap ( ) . insert ( t. to_string ( ) , class_leaked) ;
224
+ class_leaked
225
+ }
230
226
}
231
227
}
232
228
233
229
impl < T : ReferenceType , E : ThrowableType > ObjectArray < T , E > {
234
- /// Uses JNI `NewObjectArray` to create a new java object array.
230
+ /// Uses JNI `NewObjectArray` to create a new Java object array.
235
231
pub fn new < ' env > ( env : Env < ' env > , size : usize ) -> Local < ' env , Self > {
236
232
assert ! ( size <= i32 :: MAX as usize ) ; // jsize == jint == i32
237
233
let class = T :: jni_get_class ( env) . as_raw ( ) ;
@@ -242,7 +238,7 @@ impl<T: ReferenceType, E: ThrowableType> ObjectArray<T, E> {
242
238
let fill = null_mut ( ) ;
243
239
( ( * * env) . v1_2 . NewObjectArray ) ( env, size, class, fill)
244
240
} ;
245
- // Only sane exception here is an OOM exception
241
+ assert ! ( !object . is_null ( ) , " OOM" ) ;
246
242
env. exception_check :: < E > ( ) . map_err ( |_| "OOM" ) . unwrap ( ) ;
247
243
unsafe { Local :: from_raw ( env, object) }
248
244
}
@@ -256,7 +252,7 @@ impl<T: ReferenceType, E: ThrowableType> ObjectArray<T, E> {
256
252
}
257
253
}
258
254
259
- /// Uses JNI `NewObjectArray` to create a new java object array of the exact size, then sets its items
255
+ /// Uses JNI `NewObjectArray` to create a new Java object array of the exact size, then sets its items
260
256
/// with the iterator of JNI (null?) references.
261
257
pub fn new_from < ' env > ( env : Env < ' env > , elements : impl ExactSizeIterator < Item = impl AsArg < T > > ) -> Local < ' env , Self > {
262
258
let size = elements. len ( ) ;
@@ -269,13 +265,13 @@ impl<T: ReferenceType, E: ThrowableType> ObjectArray<T, E> {
269
265
array
270
266
}
271
267
272
- /// Uses JNI `GetArrayLength` to get the length of the java array.
268
+ /// Uses JNI `GetArrayLength` to get the length of the Java array.
273
269
pub fn len ( self : & Ref < ' _ , Self > ) -> usize {
274
270
let env = self . env ( ) . as_raw ( ) ;
275
271
unsafe { ( ( * * env) . v1_2 . GetArrayLength ) ( env, self . as_raw ( ) ) as usize }
276
272
}
277
273
278
- /// Uses JNI `GetArrayLength` to get the length of the java array, returns `true` if it is 0.
274
+ /// Uses JNI `GetArrayLength` to get the length of the Java array, returns `true` if it is 0.
279
275
pub fn is_empty ( self : & Ref < ' _ , Self > ) -> bool {
280
276
self . len ( ) == 0
281
277
}
0 commit comments