toad_jni/java/
object.rs

1use java::{ResultExt, Type};
2use jni::objects::{GlobalRef,
3                   JBooleanArray,
4                   JByteArray,
5                   JCharArray,
6                   JDoubleArray,
7                   JFloatArray,
8                   JIntArray,
9                   JLongArray,
10                   JObject,
11                   JObjectArray,
12                   JShortArray,
13                   JValue,
14                   JValueOwned};
15use jni::sys::jobject;
16
17use crate::java;
18
19/// A rust type that can be converted to & from a [`java::lang::Object`]
20///
21/// notably, this includes all [`java::Primitive`]s (using their wrapper classes).
22///
23/// For more information, see [`java::Type`]
24pub trait Object
25  where Self: java::Type
26{
27  /// Try to interpret an object as `Self`
28  fn upcast(e: &mut java::Env, jobj: java::lang::Object) -> Self;
29
30  /// Create an object reference from `self`
31  fn downcast(self, e: &mut java::Env) -> java::lang::Object;
32
33  /// Create an object reference from `&self`
34  fn downcast_ref(&self, e: &mut java::Env) -> java::lang::Object;
35
36  /// Try to interpret a `JValue` as `Self`
37  fn upcast_value_ref<'e>(e: &mut java::Env<'e>, jv: JValue<'e, '_>) -> Self
38    where Self: Sized
39  {
40    java::lang::Object::upcast_value_ref(e, jv).upcast_to::<Self>(e)
41  }
42
43  /// Try to interpret a `JValueOwned` as `Self`
44  fn upcast_value<'e>(e: &mut java::Env<'e>, jv: JValueOwned<'e>) -> Self
45    where Self: Sized
46  {
47    Self::upcast_value_ref(e, (&jv).into())
48  }
49
50  /// Create a `JValueOwned` from `self`
51  fn downcast_value<'e>(self, e: &mut java::Env<'e>) -> JValueOwned<'e>
52    where Self: Sized
53  {
54    self.downcast(e).downcast_value(e)
55  }
56
57  /// Use this to yield ownership of a [`java::lang::Object`]
58  /// to the JVM, for example when returning a `jobject` from a
59  /// native function.
60  fn yield_to_java(&self, e: &mut java::Env) -> jobject {
61    self.downcast_ref(e).yield_to_java(e)
62  }
63}
64
65impl Object for GlobalRef {
66  fn upcast(_: &mut java::Env, jobj: java::lang::Object) -> Self {
67    jobj.into()
68  }
69
70  fn downcast(self, _: &mut java::Env) -> java::lang::Object {
71    self.into()
72  }
73
74  fn downcast_ref(&self, e: &mut java::Env) -> java::lang::Object {
75    e.new_global_ref(self).unwrap().into()
76  }
77}
78
79impl<T> Object for Vec<T> where T: java::Object
80{
81  fn upcast(e: &mut java::Env, jobj: java::lang::Object) -> Self {
82    let arr = <&JObjectArray>::from(jobj.as_local());
83    let len = e.get_array_length(arr).unwrap_java(e) as usize;
84
85    macro_rules! go {
86      ($arr:ty => $get_region:ident) => {{
87        let arr = <&$arr>::from(jobj.as_local());
88        let mut els = Vec::new();
89        els.resize(len, Default::default());
90        e.$get_region(&arr, 0, &mut els).unwrap_java(e);
91        els.into_iter()
92           .map(|b| {
93             let val = b.downcast_value(e);
94             T::upcast_value(e, val)
95           })
96           .collect()
97      }};
98    }
99
100    match T::SIG {
101      | i8::SIG => go!(JByteArray => get_byte_array_region),
102      | i16::SIG => go!(JShortArray => get_short_array_region),
103      | i32::SIG => go!(JIntArray => get_int_array_region),
104      | i64::SIG => go!(JLongArray => get_long_array_region),
105      | f32::SIG => go!(JFloatArray => get_float_array_region),
106      | f64::SIG => go!(JDoubleArray => get_double_array_region),
107      | u16::SIG => go!(JCharArray => get_char_array_region),
108      | bool::SIG => {
109        let arr = <&JBooleanArray>::from(jobj.as_local());
110        let mut els = Vec::new();
111        els.resize(len, 0u8);
112        e.get_boolean_array_region(arr, 0, &mut els).unwrap_java(e);
113        els.into_iter()
114           .map(|b| {
115             let val = (b == jni::sys::JNI_TRUE).downcast_value(e);
116             T::upcast_value(e, val)
117           })
118           .collect()
119      },
120      | _ if jobj.is_instance_of::<Vec<java::lang::Object>>(e) => {
121        let mut vec = Vec::new();
122
123        (0..len).for_each(|ix| {
124                  let obj = e.get_object_array_element(arr, ix as i32).unwrap_java(e);
125                  vec.push(java::lang::Object::from_local(e, obj).upcast_to::<T>(e));
126                });
127
128        vec
129      },
130      | _ => {
131        let cls = e.get_object_class(&jobj).unwrap_java(e);
132        panic!("unknown array type {}",
133               java::lang::Object::from_local(e, cls).to_string(e));
134      },
135    }
136  }
137
138  fn downcast(self, e: &mut java::Env) -> java::lang::Object {
139    self.downcast_ref(e)
140  }
141
142  fn downcast_ref(&self, e: &mut java::Env) -> java::lang::Object {
143    macro_rules! go {
144      ($new_array:ident, $set_region:ident) => {{
145        let slice = self.as_slice();
146
147        // SAFETY: we checked in the match arm that the
148        // type contained in this vec is correct for the
149        // array type being constructed.
150        //
151        // The only way this could cause UB is if someone
152        // intentionally and maliciously wrote a struct with
153        // a Type::SIG matching the primitive type's; it would
154        // have to be intentional and malicious because there is
155        // no public API to declare non-class `Signature`s.
156        let slice = unsafe { core::mem::transmute::<_, &[_]>(slice) };
157
158        let arr = e.$new_array(self.len() as i32).unwrap_java(e);
159        e.$set_region(&arr, 0, slice).unwrap_java(e);
160        java::lang::Object::from_local(e, arr)
161      }};
162    }
163
164    match T::SIG {
165      | i8::SIG => go!(new_byte_array, set_byte_array_region),
166      | i16::SIG => go!(new_short_array, set_short_array_region),
167      | i32::SIG => go!(new_int_array, set_int_array_region),
168      | i64::SIG => go!(new_long_array, set_long_array_region),
169      | f32::SIG => go!(new_float_array, set_float_array_region),
170      | f64::SIG => go!(new_double_array, set_double_array_region),
171      | u16::SIG => go!(new_char_array, set_char_array_region),
172      | bool::SIG => go!(new_boolean_array, set_boolean_array_region),
173      | _ => {
174        let arr = e.new_object_array(self.len() as i32, java::lang::Object::SIG, JObject::null())
175                   .unwrap_java(e);
176        let arr_ref = &arr;
177        self.iter().enumerate().for_each(|(ix, o)| {
178                                 let val = o.downcast_ref(e);
179                                 e.set_object_array_element(arr_ref, ix as i32, &val)
180                                  .unwrap_java(e);
181                               });
182
183        java::lang::Object::from_local(e, arr)
184      },
185    }
186  }
187}
188
189impl<T> Object for T where T: java::Primitive
190{
191  fn upcast(e: &mut java::Env, jobj: java::lang::Object) -> Self {
192    let w = <T as java::Primitive>::PrimitiveWrapper::upcast(e, jobj);
193    T::from_primitive_wrapper(e, w)
194  }
195
196  fn downcast(self, e: &mut java::Env) -> java::lang::Object {
197    self.to_primitive_wrapper(e).downcast(e)
198  }
199
200  fn downcast_ref(&self, e: &mut java::Env) -> java::lang::Object {
201    self.to_primitive_wrapper(e).downcast(e)
202  }
203
204  fn upcast_value_ref<'e>(_: &mut java::Env<'e>, jv: JValue<'e, '_>) -> Self
205    where Self: Sized
206  {
207    T::from_jvalue_ref(jv)
208  }
209
210  fn upcast_value(_: &mut java::Env, jv: JValueOwned) -> Self
211    where Self: Sized
212  {
213    T::from_jvalue(jv)
214  }
215
216  fn downcast_value<'e>(self, _: &mut java::Env<'e>) -> JValueOwned<'e>
217    where Self: Sized
218  {
219    self.into_jvalue()
220  }
221}
222
223impl Object for () {
224  fn upcast(_: &mut java::Env, _: java::lang::Object) -> Self {
225    ()
226  }
227
228  fn downcast(self, e: &mut java::Env) -> java::lang::Object {
229    java::lang::Object::from_local(e, JObject::null())
230  }
231
232  fn downcast_ref(&self, e: &mut java::Env) -> java::lang::Object {
233    ().downcast(e)
234  }
235
236  fn upcast_value_ref<'e>(_: &mut java::Env<'e>, jv: JValue<'e, '_>) -> Self
237    where Self: Sized
238  {
239    jv.v().unwrap()
240  }
241
242  fn upcast_value<'e>(_: &mut java::Env<'e>, jv: JValueOwned<'e>) -> Self
243    where Self: Sized
244  {
245    jv.v().unwrap()
246  }
247
248  fn downcast_value<'e>(self, _: &mut java::Env<'e>) -> JValueOwned<'e>
249    where Self: Sized
250  {
251    JValueOwned::Void
252  }
253}