1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use jni_sys::*;

/// JNI bindings rely on this type being accurate.
///
/// **unsafe**:  static_with_jni_type must pass a string terminated by '\0'.  Failing to do so is a soundness bug, as
/// the string is passed directly to JNI as a raw pointer!  Additionally, passing the wrong type may be a soundness bug
/// as although the Android JVM will simply panic and abort, I've no idea if that's a guarantee or not.
///
/// Why the awkward callback style instead of returning `&'static str`?  Arrays of arrays may need to dynamically
/// construct their type strings, which would need to leak.  Worse, we can't easily intern those strings via
/// lazy_static without running into:
///
/// ```text
/// error[E0401]: can't use generic parameters from outer function
/// ```
pub unsafe trait JniType {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R;
}

unsafe impl JniType for () {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
        callback("V\0")
    }
}
unsafe impl JniType for bool {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
        callback("Z\0")
    }
}
unsafe impl JniType for jbyte {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
        callback("B\0")
    }
}
unsafe impl JniType for jchar {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
        callback("C\0")
    }
}
unsafe impl JniType for jshort {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
        callback("S\0")
    }
}
unsafe impl JniType for jint {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
        callback("I\0")
    }
}
unsafe impl JniType for jlong {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
        callback("J\0")
    }
}
unsafe impl JniType for jfloat {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
        callback("F\0")
    }
}
unsafe impl JniType for jdouble {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
        callback("D\0")
    }
}
unsafe impl JniType for &str {
    fn static_with_jni_type<R>(callback: impl FnOnce(&str) -> R) -> R {
        callback("Ljava/lang/String;\0")
    }
}