• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::sys::jsize;
2 use log::error;
3 
4 use std::ptr::NonNull;
5 
6 use crate::objects::release_mode::ReleaseMode;
7 use crate::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
8 use crate::{errors::*, objects::JObject, sys, JNIEnv};
9 
10 /// Trait to define type array access/release
11 pub trait TypeArray {
12     /// getter
get(env: &JNIEnv, obj: JObject, is_copy: &mut jboolean) -> Result<*mut Self>13     fn get(env: &JNIEnv, obj: JObject, is_copy: &mut jboolean) -> Result<*mut Self>;
14 
15     /// releaser
release(env: &JNIEnv, obj: JObject, ptr: NonNull<Self>, mode: i32) -> Result<()>16     fn release(env: &JNIEnv, obj: JObject, ptr: NonNull<Self>, mode: i32) -> Result<()>;
17 }
18 
19 // TypeArray builder
20 macro_rules! type_array {
21     ( $jni_type:ty, $jni_get:tt, $jni_release:tt ) => {
22         /// $jni_type array access/release impl
23         impl TypeArray for $jni_type {
24             /// Get Java $jni_type array
25             fn get(env: &JNIEnv, obj: JObject, is_copy: &mut jboolean) -> Result<*mut Self> {
26                 let internal = env.get_native_interface();
27                 // Even though this method may throw OoME, use `jni_unchecked`
28                 // instead of `jni_non_null_call` to remove (a slight) overhead
29                 // of exception checking. An error will still be detected as a `null`
30                 // result inside AutoArray ctor. Also, modern Hotspot in case of lack
31                 // of memory will return null and won't throw an exception:
32                 // https://sourcegraph.com/github.com/openjdk/jdk/-/blob/src/hotspot/share/memory/allocation.hpp#L488-489
33                 let res = jni_unchecked!(internal, $jni_get, *obj, is_copy);
34                 Ok(res)
35             }
36 
37             /// Release Java $jni_type array
38             fn release(env: &JNIEnv, obj: JObject, ptr: NonNull<Self>, mode: i32) -> Result<()> {
39                 let internal = env.get_native_interface();
40                 jni_unchecked!(internal, $jni_release, *obj, ptr.as_ptr(), mode as i32);
41                 Ok(())
42             }
43         }
44     };
45 }
46 
47 type_array!(jint, GetIntArrayElements, ReleaseIntArrayElements);
48 type_array!(jlong, GetLongArrayElements, ReleaseLongArrayElements);
49 type_array!(jbyte, GetByteArrayElements, ReleaseByteArrayElements);
50 type_array!(
51     jboolean,
52     GetBooleanArrayElements,
53     ReleaseBooleanArrayElements
54 );
55 type_array!(jchar, GetCharArrayElements, ReleaseCharArrayElements);
56 type_array!(jshort, GetShortArrayElements, ReleaseShortArrayElements);
57 type_array!(jfloat, GetFloatArrayElements, ReleaseFloatArrayElements);
58 type_array!(jdouble, GetDoubleArrayElements, ReleaseDoubleArrayElements);
59 
60 /// Auto-release wrapper for pointer-based generic arrays.
61 ///
62 /// This wrapper is used to wrap pointers returned by Get<Type>ArrayElements.
63 /// While wrapped, the object can be accessed via the `From` impl.
64 ///
65 /// AutoArray provides automatic array release through a call to appropriate
66 /// Release<Type>ArrayElements when it goes out of scope.
67 pub struct AutoArray<'a: 'b, 'b, T: TypeArray> {
68     obj: JObject<'a>,
69     ptr: NonNull<T>,
70     mode: ReleaseMode,
71     is_copy: bool,
72     env: &'b JNIEnv<'a>,
73 }
74 
75 impl<'a, 'b, T: TypeArray> AutoArray<'a, 'b, T> {
new(env: &'b JNIEnv<'a>, obj: JObject<'a>, mode: ReleaseMode) -> Result<Self>76     pub(crate) fn new(env: &'b JNIEnv<'a>, obj: JObject<'a>, mode: ReleaseMode) -> Result<Self> {
77         let mut is_copy: jboolean = 0xff;
78         Ok(AutoArray {
79             obj,
80             ptr: {
81                 let ptr = T::get(env, obj, &mut is_copy)?;
82                 NonNull::new(ptr).ok_or(Error::NullPtr("Non-null ptr expected"))?
83             },
84             mode,
85             is_copy: is_copy == sys::JNI_TRUE,
86             env,
87         })
88     }
89 
90     /// Get a reference to the wrapped pointer
as_ptr(&self) -> *mut T91     pub fn as_ptr(&self) -> *mut T {
92         self.ptr.as_ptr()
93     }
94 
95     /// Commits the changes to the array, if it is a copy
commit(&self) -> Result<()>96     pub fn commit(&self) -> Result<()> {
97         self.release_array_elements(sys::JNI_COMMIT)
98     }
99 
release_array_elements(&self, mode: i32) -> Result<()>100     fn release_array_elements(&self, mode: i32) -> Result<()> {
101         T::release(self.env, self.obj, self.ptr, mode)
102     }
103 
104     /// Don't commit the changes to the array on release (if it is a copy).
105     /// This has no effect if the array is not a copy.
106     /// This method is useful to change the release mode of an array originally created
107     /// with `ReleaseMode::CopyBack`.
discard(&mut self)108     pub fn discard(&mut self) {
109         self.mode = ReleaseMode::NoCopyBack;
110     }
111 
112     /// Indicates if the array is a copy or not
is_copy(&self) -> bool113     pub fn is_copy(&self) -> bool {
114         self.is_copy
115     }
116 
117     /// Returns the array size
size(&self) -> Result<jsize>118     pub fn size(&self) -> Result<jsize> {
119         self.env.get_array_length(*self.obj)
120     }
121 }
122 
123 impl<'a, 'b, T: TypeArray> Drop for AutoArray<'a, 'b, T> {
drop(&mut self)124     fn drop(&mut self) {
125         let res = self.release_array_elements(self.mode as i32);
126         match res {
127             Ok(()) => {}
128             Err(e) => error!("error releasing array: {:#?}", e),
129         }
130     }
131 }
132 
133 impl<'a, T: TypeArray> From<&'a AutoArray<'a, '_, T>> for *mut T {
from(other: &'a AutoArray<T>) -> *mut T134     fn from(other: &'a AutoArray<T>) -> *mut T {
135         other.as_ptr()
136     }
137 }
138