prebindgen_jni_runtime/
box_helpers.rs1use std::sync::OnceLock;
15
16use jni::{
17 objects::{GlobalRef, JObject, JStaticMethodID},
18 signature::ReturnType,
19 sys::jvalue,
20 JNIEnv,
21};
22
23struct BoxClass {
27 class: GlobalRef,
28 value_of: JStaticMethodID,
29}
30
31fn cached<'c>(
32 env: &mut JNIEnv,
33 cell: &'c OnceLock<BoxClass>,
34 class_name: &str,
35 value_of_sig: &str,
36) -> Result<&'c BoxClass, String> {
37 if let Some(b) = cell.get() {
38 return Ok(b);
39 }
40 let class = env
41 .find_class(class_name)
42 .map_err(|e| format!("find box class {class_name}: {e}"))?;
43 let value_of = env
44 .get_static_method_id(&class, "valueOf", value_of_sig)
45 .map_err(|e| format!("resolve {class_name}.valueOf: {e}"))?;
46 let class = env
47 .new_global_ref(&class)
48 .map_err(|e| format!("global-ref box class {class_name}: {e}"))?;
49 let _ = cell.set(BoxClass { class, value_of });
52 Ok(cell.get().expect("cell was just set"))
53}
54
55macro_rules! box_helper {
56 ($name:ident, $prim:ty, $field:ident, $class:literal, $sig:literal) => {
57 #[doc = concat!("Box a `", stringify!($prim), "` into `", $class, "` via cached `valueOf`.")]
58 pub fn $name<'local>(
59 env: &mut JNIEnv<'local>,
60 v: $prim,
61 ) -> Result<JObject<'local>, String> {
62 static CELL: OnceLock<BoxClass> = OnceLock::new();
63 let b = cached(env, &CELL, $class, $sig)?;
64 unsafe {
67 env.call_static_method_unchecked(
68 &b.class,
69 b.value_of,
70 ReturnType::Object,
71 &[jvalue { $field: v }],
72 )
73 }
74 .and_then(|r| r.l())
75 .map_err(|e| format!("box {}: {}", $class, e))
76 }
77 };
78}
79
80box_helper!(
81 box_jboolean,
82 jni::sys::jboolean,
83 z,
84 "java/lang/Boolean",
85 "(Z)Ljava/lang/Boolean;"
86);
87box_helper!(
88 box_jbyte,
89 jni::sys::jbyte,
90 b,
91 "java/lang/Byte",
92 "(B)Ljava/lang/Byte;"
93);
94box_helper!(
95 box_jchar,
96 jni::sys::jchar,
97 c,
98 "java/lang/Character",
99 "(C)Ljava/lang/Character;"
100);
101box_helper!(
102 box_jshort,
103 jni::sys::jshort,
104 s,
105 "java/lang/Short",
106 "(S)Ljava/lang/Short;"
107);
108box_helper!(
109 box_jint,
110 jni::sys::jint,
111 i,
112 "java/lang/Integer",
113 "(I)Ljava/lang/Integer;"
114);
115box_helper!(
116 box_jlong,
117 jni::sys::jlong,
118 j,
119 "java/lang/Long",
120 "(J)Ljava/lang/Long;"
121);
122box_helper!(
123 box_jfloat,
124 jni::sys::jfloat,
125 f,
126 "java/lang/Float",
127 "(F)Ljava/lang/Float;"
128);
129box_helper!(
130 box_jdouble,
131 jni::sys::jdouble,
132 d,
133 "java/lang/Double",
134 "(D)Ljava/lang/Double;"
135);