1use jni::{
2 JNIEnv,
3 objects::{GlobalRef, JByteArray, JObject, JValue, JValueGen, ReleaseMode},
4 signature::{Primitive, ReturnType},
5};
6
7#[derive(Clone, Copy)]
8pub enum SignatureComp {
9 Class(ClassDecl),
10 Boolean,
11 Byte,
12 Char,
13 Short,
14 Int,
15 Long,
16 Float,
17 Double,
18 Void,
19 ArrayBoolean,
20 ArrayByte,
21 ArrayChar,
22 ArrayShort,
23 ArrayInt,
24 ArrayLong,
25 ArrayFloat,
26 ArrayDouble,
27}
28impl From<ClassDecl> for SignatureComp {
29 fn from(value: ClassDecl) -> Self {
30 Self::Class(value)
31 }
32}
33impl From<SignatureComp> for ReturnType {
34 fn from(value: SignatureComp) -> Self {
35 match value {
36 SignatureComp::Class(class_decl) if class_decl.0.starts_with('[') => ReturnType::Array,
37 SignatureComp::Class(_) => ReturnType::Object,
38 SignatureComp::Boolean => ReturnType::Primitive(Primitive::Boolean),
39 SignatureComp::Byte => ReturnType::Primitive(Primitive::Byte),
40 SignatureComp::Char => ReturnType::Primitive(Primitive::Char),
41 SignatureComp::Short => ReturnType::Primitive(Primitive::Short),
42 SignatureComp::Int => ReturnType::Primitive(Primitive::Int),
43 SignatureComp::Long => ReturnType::Primitive(Primitive::Long),
44 SignatureComp::Float => ReturnType::Primitive(Primitive::Float),
45 SignatureComp::Double => ReturnType::Primitive(Primitive::Double),
46 SignatureComp::Void => ReturnType::Primitive(Primitive::Void),
47 SignatureComp::ArrayBoolean => ReturnType::Array,
48 SignatureComp::ArrayByte => ReturnType::Array,
49 SignatureComp::ArrayChar => ReturnType::Array,
50 SignatureComp::ArrayShort => ReturnType::Array,
51 SignatureComp::ArrayInt => ReturnType::Array,
52 SignatureComp::ArrayLong => ReturnType::Array,
53 SignatureComp::ArrayFloat => ReturnType::Array,
54 SignatureComp::ArrayDouble => ReturnType::Array,
55 }
56 }
57}
58impl SignatureComp {
59 fn for_finding(self) -> &'static str {
60 match self {
61 SignatureComp::Class(class_decl) => class_decl.for_finding(),
62 other => other.as_str(),
63 }
64 }
65
66 fn as_str(self) -> &'static str {
67 match self {
68 SignatureComp::Class(ClassDecl(class_decl)) => class_decl,
69 SignatureComp::Boolean => "Z",
70 SignatureComp::Byte => "B",
71 SignatureComp::Char => "C",
72 SignatureComp::Short => "S",
73 SignatureComp::Int => "I",
74 SignatureComp::Long => "J",
75 SignatureComp::Float => "F",
76 SignatureComp::Double => "D",
77 SignatureComp::Void => "V",
78 SignatureComp::ArrayBoolean => "[Z",
79 SignatureComp::ArrayByte => "[B",
80 SignatureComp::ArrayChar => "[C",
81 SignatureComp::ArrayShort => "[S",
82 SignatureComp::ArrayInt => "[I",
83 SignatureComp::ArrayLong => "[J",
84 SignatureComp::ArrayFloat => "[F",
85 SignatureComp::ArrayDouble => "[D",
86 }
87 }
88}
89
90#[derive(Clone, Copy)]
91pub struct ClassDecl(pub &'static str);
92impl ClassDecl {
93 fn for_finding(self) -> &'static str {
94 if !self.0.is_empty() && &self.0[0..1] == "[" {
95 return self.0;
96 }
97
98 &self.0[..(self.0.len() - 1)][1..]
99 }
100}
101
102pub trait Method {
103 type Param: AsParam;
104 type Return: FromValue;
105
106 const NAME: &str;
107
108 fn call(self_: &JObject, env: &mut JNIEnv, params: Self::Param) -> JResult<Self::Return> {
109 let signature = make_signature(&Self::Param::signature(), Self::Return::signature());
110 let param = params.as_param(env)?;
111 let param = borrow_params(¶m);
112 let r = env.call_method(self_, Self::NAME, &signature, param.as_slice())?;
113
114 match r {
115 JValueGen::Object(obj) if obj.is_null() => Ok(FromValue::from_null()?),
116 JValueGen::Object(obj) => Ok(FromValue::from_object(env.new_global_ref(obj)?, env)?),
117 JValueGen::Byte(value) => Ok(FromValue::from_value(JValueGen::Byte(value))?),
118 JValueGen::Char(value) => Ok(FromValue::from_value(JValueGen::Char(value))?),
119 JValueGen::Short(value) => Ok(FromValue::from_value(JValueGen::Short(value))?),
120 JValueGen::Int(value) => Ok(FromValue::from_value(JValueGen::Int(value))?),
121 JValueGen::Long(value) => Ok(FromValue::from_value(JValueGen::Long(value))?),
122 JValueGen::Bool(value) => Ok(FromValue::from_value(JValueGen::Bool(value))?),
123 JValueGen::Float(value) => Ok(FromValue::from_value(JValueGen::Float(value))?),
124 JValueGen::Double(value) => Ok(FromValue::from_value(JValueGen::Double(value))?),
125 JValueGen::Void => Ok(FromValue::from_value(JValueGen::Void)?),
126 }
127 }
128}
129
130pub trait StaticMethod {
131 type Param: AsParam;
132 type Return: FromValue;
133
134 const NAME: &str;
135
136 fn call(self_: ClassDecl, env: &mut JNIEnv, params: Self::Param) -> JResult<Self::Return> {
137 let signature = make_signature(&Self::Param::signature(), Self::Return::signature());
138 let param = params.as_param(env)?;
139 let param = borrow_params(¶m);
140 let r = env.call_static_method(
141 self_.for_finding(),
142 Self::NAME,
143 &signature,
144 param.as_slice(),
145 )?;
146
147 match r {
148 JValueGen::Object(obj) if obj.is_null() => Ok(FromValue::from_null()?),
149 JValueGen::Object(obj) => Ok(FromValue::from_object(env.new_global_ref(obj)?, env)?),
150 JValueGen::Byte(value) => Ok(FromValue::from_value(JValueGen::Byte(value))?),
151 JValueGen::Char(value) => Ok(FromValue::from_value(JValueGen::Char(value))?),
152 JValueGen::Short(value) => Ok(FromValue::from_value(JValueGen::Short(value))?),
153 JValueGen::Int(value) => Ok(FromValue::from_value(JValueGen::Int(value))?),
154 JValueGen::Long(value) => Ok(FromValue::from_value(JValueGen::Long(value))?),
155 JValueGen::Bool(value) => Ok(FromValue::from_value(JValueGen::Bool(value))?),
156 JValueGen::Float(value) => Ok(FromValue::from_value(JValueGen::Float(value))?),
157 JValueGen::Double(value) => Ok(FromValue::from_value(JValueGen::Double(value))?),
158 JValueGen::Void => Ok(FromValue::from_value(JValueGen::Void)?),
159 }
160 }
161}
162
163pub trait Constructible {
164 type Param: AsParam;
165 type Return: FromValue;
166
167 fn call_new(self_: ClassDecl, env: &mut JNIEnv, params: Self::Param) -> JResult<Self::Return> {
168 let signature = make_signature(&Self::Param::signature(), <() as FromValue>::signature());
169 let param = params.as_param(env)?;
170 let param = borrow_params(¶m);
171 let obj = env.new_object(self_.for_finding(), &signature, param.as_slice())?;
172
173 FromValue::from_object(env.new_global_ref(obj)?, env)
174 }
175}
176
177pub trait AsParam {
178 fn signature() -> Vec<SignatureComp>;
179 fn as_param<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<Vec<JValueGen<JObject<'a>>>>;
180}
181impl<T1> AsParam for T1
182where
183 T1: ToValue,
184{
185 fn signature() -> Vec<SignatureComp> {
186 vec![T1::signature()]
187 }
188
189 fn as_param<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<Vec<JValueGen<JObject<'a>>>> {
190 Ok(vec![self.to_value(env)?])
191 }
192}
193impl<T1, T2> AsParam for (T1, T2)
194where
195 T1: ToValue,
196 T2: ToValue,
197{
198 fn signature() -> Vec<SignatureComp> {
199 vec![T1::signature(), T2::signature()]
200 }
201
202 fn as_param<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<Vec<JValueGen<JObject<'a>>>> {
203 Ok(vec![self.0.to_value(env)?, self.1.to_value(env)?])
204 }
205}
206impl<T1, T2, T3> AsParam for (T1, T2, T3)
207where
208 T1: ToValue,
209 T2: ToValue,
210 T3: ToValue,
211{
212 fn signature() -> Vec<SignatureComp> {
213 vec![T1::signature(), T2::signature(), T3::signature()]
214 }
215
216 fn as_param<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<Vec<JValueGen<JObject<'a>>>> {
217 Ok(vec![
218 self.0.to_value(env)?,
219 self.1.to_value(env)?,
220 self.2.to_value(env)?,
221 ])
222 }
223}
224
225pub struct NoParam;
226impl AsParam for NoParam {
227 fn signature() -> Vec<SignatureComp> {
228 vec![]
229 }
230
231 fn as_param<'a>(&self, _env: &mut JNIEnv<'a>) -> JResult<Vec<JValueGen<JObject<'a>>>> {
232 Ok(vec![])
233 }
234}
235
236pub trait ToValue: Sized {
237 fn signature() -> SignatureComp;
238 fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>>;
239}
240impl<T: ToValue> ToValue for &T {
241 fn signature() -> SignatureComp {
242 T::signature()
243 }
244
245 fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
246 T::to_value(self, env)
247 }
248}
249impl<T: ToValue> ToValue for Option<T> {
250 fn signature() -> SignatureComp {
251 T::signature()
252 }
253
254 fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
255 Ok(match self {
256 Some(self_) => self_.to_value(env)?,
257 None => JObject::null().into(),
258 })
259 }
260}
261impl ToValue for &str {
262 fn signature() -> SignatureComp {
263 <String as FromValue>::signature()
264 }
265
266 fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
267 Ok(JValueGen::Object(env.new_string(self)?.into()))
268 }
269}
270impl ToValue for &[&str] {
271 fn signature() -> SignatureComp {
272 ClassDecl("[Ljava/lang/String;").into()
273 }
274
275 fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
276 let array = env.new_object_array(
277 self.len() as i32,
278 <&str as ToValue>::signature().for_finding(),
279 JObject::null(),
280 )?;
281
282 for (index, value) in self.iter().enumerate() {
283 env.set_object_array_element(&array, index as i32, env.new_string(*value)?)?;
284 }
285
286 let array: JObject = array.into();
287 Ok(array.into())
288 }
289}
290impl ToValue for &[u8] {
291 fn signature() -> SignatureComp {
292 SignatureComp::ArrayByte
293 }
294
295 fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
296 let bytes: JObject = env.byte_array_from_slice(self)?.into();
297 Ok(bytes.into())
298 }
299}
300impl ToValue for Vec<u16> {
301 fn signature() -> SignatureComp {
302 SignatureComp::ArrayChar
303 }
304
305 fn to_value<'a>(&self, env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
306 let chars = env.new_char_array(self.len() as i32)?;
307 unsafe {
308 let mut chars_write = env.get_array_elements(&chars, ReleaseMode::CopyBack)?;
309 chars_write.copy_from_slice(self);
310 }
311 let chars: JObject = chars.into();
312 Ok(chars.into())
313 }
314}
315impl ToValue for i32 {
316 fn signature() -> SignatureComp {
317 SignatureComp::Int
318 }
319
320 fn to_value<'a>(&self, _env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
321 Ok((*self).into())
322 }
323}
324impl ToValue for bool {
325 fn signature() -> SignatureComp {
326 SignatureComp::Boolean
327 }
328
329 fn to_value<'a>(&self, _env: &mut JNIEnv<'a>) -> JResult<JValueGen<JObject<'a>>> {
330 Ok((*self).into())
331 }
332}
333
334pub trait FromValue: Sized {
335 fn signature() -> SignatureComp;
336
337 fn from_object(value: GlobalRef, env: &mut JNIEnv) -> JResult<Self> {
338 let _ = (value, env);
339 Err(jni::errors::Error::WrongJValueType("primitive", "object"))
340 }
341
342 fn from_value(value: JValue) -> JResult<Self> {
343 Err(jni::errors::Error::WrongJValueType(
344 "object",
345 value.type_name(),
346 ))
347 }
348
349 fn from_null() -> JResult<Self> {
350 Err(jni::errors::Error::WrongJValueType("object", "null"))
351 }
352}
353impl<T: FromValue> FromValue for Option<T> {
354 fn signature() -> SignatureComp {
355 T::signature()
356 }
357
358 fn from_null() -> JResult<Self> {
359 Ok(Self::None)
360 }
361
362 fn from_object(value: GlobalRef, env: &mut JNIEnv) -> JResult<Self> {
363 Ok(Some(T::from_object(value, env)?))
364 }
365
366 fn from_value(value: JValue) -> JResult<Self> {
367 Ok(Some(T::from_value(value)?))
368 }
369}
370impl FromValue for () {
371 fn signature() -> SignatureComp {
372 SignatureComp::Void
373 }
374
375 fn from_value(value: JValue) -> JResult<Self> {
376 value.v()
377 }
378
379 fn from_null() -> JResult<Self> {
380 Ok(())
381 }
382}
383impl FromValue for bool {
384 fn signature() -> SignatureComp {
385 SignatureComp::Boolean
386 }
387
388 fn from_value(value: JValue) -> JResult<Self> {
389 value.z()
390 }
391}
392impl FromValue for String {
393 fn signature() -> SignatureComp {
394 ClassDecl("Ljava/lang/String;").into()
395 }
396
397 fn from_object(value: GlobalRef, env: &mut JNIEnv) -> JResult<Self> {
398 let string = env.get_string((&value as &JObject).into())?;
399 Ok(string.to_string_lossy().into_owned())
400 }
401}
402impl FromValue for Vec<u8> {
403 fn signature() -> SignatureComp {
404 SignatureComp::ArrayByte
405 }
406
407 fn from_object(value: GlobalRef, env: &mut JNIEnv) -> JResult<Self> {
408 let value: &JByteArray = value.as_obj().into();
409 let len = env.get_array_length(value)? as usize;
410 let mut buf = vec![0; len];
411 env.get_byte_array_region(value, 0, &mut buf)?;
412
413 Ok(buf.into_iter().map(|x| x as u8).collect())
414 }
415}
416
417fn make_signature(params: &[SignatureComp], result: SignatureComp) -> String {
418 use std::fmt::Write;
419 let mut w = String::new();
420 write!(w, "(").unwrap();
421 for param in params {
422 write!(w, "{}", param.as_str()).unwrap();
423 }
424 write!(w, "){}", result.as_str()).unwrap();
425 w
426}
427
428fn borrow_params<'a, 'b>(
429 params: &'a Vec<JValueGen<JObject<'b>>>,
430) -> Vec<JValueGen<&'a JObject<'b>>> {
431 params
432 .iter()
433 .map(|value| match value {
434 JValueGen::Object(value) => JValueGen::Object(value),
435 JValueGen::Byte(value) => JValueGen::Byte(*value),
436 JValueGen::Char(value) => JValueGen::Char(*value),
437 JValueGen::Short(value) => JValueGen::Short(*value),
438 JValueGen::Int(value) => JValueGen::Int(*value),
439 JValueGen::Long(value) => JValueGen::Long(*value),
440 JValueGen::Bool(value) => JValueGen::Bool(*value),
441 JValueGen::Float(value) => JValueGen::Float(*value),
442 JValueGen::Double(value) => JValueGen::Double(*value),
443 JValueGen::Void => JValueGen::Void,
444 })
445 .collect()
446}
447
448pub type JResult<T> = Result<T, jni::errors::Error>;