java_spaghetti/
jni_type.rs

1use jni_sys::*;
2
3/// JNI bindings rely on this type being accurate.
4///
5/// **unsafe**:  static_with_jni_type must pass a string terminated by '\0'.  Failing to do so is a soundness bug, as
6/// the string is passed directly to JNI as a raw pointer!  Additionally, passing the wrong type may be a soundness bug
7/// as although the Android JVM will simply panic and abort, I've no idea if that's a guarantee or not.
8///
9/// Why the awkward callback style instead of returning `&'static str`?  Arrays of arrays may need to dynamically
10/// construct their type strings, which would need to leak.  Worse, we can't easily intern those strings via
11/// lazy_static without running into:
12///
13/// ```text
14/// error[E0401]: can't use generic parameters from outer function
15/// ```
16pub unsafe trait JniType {
17    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R;
18}
19
20unsafe impl JniType for () {
21    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
22        callback("V\0")
23    }
24}
25unsafe impl JniType for bool {
26    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
27        callback("Z\0")
28    }
29}
30unsafe impl JniType for jbyte {
31    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
32        callback("B\0")
33    }
34}
35unsafe impl JniType for jchar {
36    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
37        callback("C\0")
38    }
39}
40unsafe impl JniType for jshort {
41    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
42        callback("S\0")
43    }
44}
45unsafe impl JniType for jint {
46    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
47        callback("I\0")
48    }
49}
50unsafe impl JniType for jlong {
51    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
52        callback("J\0")
53    }
54}
55unsafe impl JniType for jfloat {
56    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
57        callback("F\0")
58    }
59}
60unsafe impl JniType for jdouble {
61    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
62        callback("D\0")
63    }
64}
65unsafe impl JniType for &str {
66    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
67        callback("Ljava/lang/String;\0")
68    }
69}