1#![feature(anonymous_lifetime_in_impl_trait)]
2
3use jni::objects::JValue;
4use jni::sys::*;
5
6pub use jni;
7pub use jni::sys::{jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort};
8pub use jni::JNIEnv;
9
10pub mod export {
11 pub use const_format;
12 pub use paste;
13}
14
15mod primitives;
16
17pub unsafe trait IsA<T>{
20 unsafe fn as_ref(&self) -> &T;
21}
22
23pub unsafe trait JReturnType {
24 const SIGNATURE: &'static str;
25 const NAME: &'static str;
26 const JNI_RETURN_TY: jni::signature::ReturnType;
27
28 unsafe fn from_jvalue(env: &mut JNIEnv, value: jvalue) -> Self;
29}
30
31unsafe impl JReturnType for () {
32 const SIGNATURE: &'static str = "V";
33 const NAME: &'static str = "void";
34 const JNI_RETURN_TY: jni::signature::ReturnType =
35 jni::signature::ReturnType::Primitive(jni::signature::Primitive::Void);
36
37 unsafe fn from_jvalue(_env: &mut JNIEnv, _value: jvalue) -> Self {
38 ()
39 }
40}
41
42pub unsafe trait JBindingType {
45 const SIGNATURE: &'static str;
46 const NAME: &'static str;
47
48 unsafe fn to_jvalue(&self) -> jvalue;
49 unsafe fn to_jvalue_ref<'obj_ref>(&'obj_ref self) -> JValue<'_, 'obj_ref>;
50}
51
52#[macro_export]
53macro_rules! import_class {
54 (
55 $sig: expr;
56 $name: ident;
57 $(extends $parent_class: ty;)?
58 $(implements $($parent_interface: ty),+;)?
59 $(
60 constructor ($($ctor_arg:ident : $ctor_arg_ty:ty),*);
61 )?
62 $(
63 field $field:ident : $field_ty:ty;
64 )*
65 $(
66 static fn $static_method:ident ($($static_arg:ident : $static_arg_ty:ty),*) -> $static_ret:ty;
67 )*
68 $(
69 $(#[doc=$doc:expr])*
70 fn $method:ident (&self $(, $arg:ident : $arg_ty:ty)*) -> $ret:ty;
71 )*
72 ) => {
73 #[repr(transparent)]
74 #[derive(Debug, Clone)]
75 pub struct $name{
76 _obj: $crate::jni::objects::GlobalRef,
77 }
78
79 unsafe impl $crate::JBindingType for $name {
80 const SIGNATURE: &'static str = concat!("L", $sig, ";");
81 const NAME: &'static str = $sig;
82
83 unsafe fn to_jvalue(&self) -> $crate::jni::sys::jvalue {
84 $crate::jni::sys::jvalue{
85 l: self._obj.as_obj().as_raw()
86 }
87 }
88
89 unsafe fn to_jvalue_ref<'obj_ref>(&'obj_ref self) -> $crate::jni::objects::JValue<'_, 'obj_ref>{
90 $crate::jni::objects::JValue::Object(
91 self._obj.as_obj()
92 )
93 }
94 }
95
96 unsafe impl $crate::JReturnType for $name {
97 const SIGNATURE: &'static str = <Self as $crate::JBindingType>::SIGNATURE;
98 const NAME: &'static str = <Self as $crate::JBindingType>::NAME;
99 const JNI_RETURN_TY: jni::signature::ReturnType = jni::signature::ReturnType::Object;
100
101 unsafe fn from_jvalue(env: &mut$crate::JNIEnv, value: $crate::jni::sys::jvalue) -> Self {
102 let o = $crate::jni::objects::JObject::from_raw(value.l);
103 let r = env.new_global_ref(o).expect("failed to create global ref");
104 Self {
105 _obj: r,
106 }
107 }
108 }
109
110 unsafe impl $crate::IsA<$name> for $name{
111 unsafe fn as_ref(&self) -> &$name{
112 self
113 }
114 }
115
116 unsafe impl $crate::IsA<$name> for &$name{
117 unsafe fn as_ref(&self) -> &$name{
118 self
119 }
120 }
121
122
123 $(
124 impl ::core::convert::AsRef<$parent_class> for $name{
125 fn as_ref(&self) -> &$parent_class{
126 unsafe{
127 core::mem::transmute(self)
128 }
129 }
130 }
131
132 impl ::core::ops::Deref for $name{
133 type Target = $parent_class;
134 fn deref(&self) -> &$parent_class{
135 unsafe{
136 core::mem::transmute(self)
137 }
138 }
139 }
140
141 impl From<$name> for $parent_class{
142 fn from(value: $name) -> $parent_class{
143 unsafe{
144 core::mem::transmute(value)
145 }
146 }
147 }
148
149 unsafe impl $crate::IsA<$parent_class> for $name{
150 unsafe fn as_ref(&self) -> &$parent_class{
151 ::core::convert::AsRef::as_ref(self)
152 }
153 }
154
155 unsafe impl $crate::IsA<$parent_class> for &$name{
156 unsafe fn as_ref(&self) -> &$parent_class{
157 ::core::convert::AsRef::as_ref(self)
158 }
159 }
160 )?
161
162 $(
163 $(
164 impl ::core::convert::AsRef<$parent_interface> for $name{
165 fn as_ref(&self) -> &$parent_interface{
166 unsafe{
167 core::mem::transmute(self)
168 }
169 }
170 }
171
172 impl From<$name> for $parent_interface{
173 fn from(value: $name) -> $parent_interface{
174 unsafe{
175 core::mem::transmute(value)
176 }
177 }
178 }
179
180 unsafe impl $crate::IsA<$parent_interface> for $name{
181 unsafe fn as_ref(&self) -> &$parent_interface{
182 ::core::convert::AsRef::as_ref(self)
183 }
184 }
185
186 unsafe impl $crate::IsA<$parent_interface> for &$name{
187 unsafe fn as_ref(&self) -> &$parent_interface{
188 ::core::convert::AsRef::as_ref(self)
189 }
190 }
191 )*
192 )?
193
194 #[allow(unused)]
195 impl $name {
196 #[allow(dead_code)]
197 fn class<'local>(env: &mut $crate::jni::JNIEnv<'local>) -> Result<$crate::jni::objects::JClass<'local>, $crate::jni::errors::Error>{
198 static CACHE: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
199
200 let id = CACHE.load(core::sync::atomic::Ordering::Relaxed);
201
202 let mut env_ptr = id >> 32;
203 let mut class_ptr = id & 0xFFFFFFFF;
204
205 if env_ptr == 0 || env_ptr != env.get_raw() as u64 {
206 env_ptr = env.get_raw() as u64;
207
208 let class = env
209 .find_class(<Self as $crate::JBindingType>::NAME)?;
210
211 class_ptr = class.as_raw() as u64;
212
213 let cache = (env_ptr << 32) | class_ptr;
214
215 CACHE.store(cache, core::sync::atomic::Ordering::Relaxed);
216 };
217
218 unsafe{
219 return Ok($crate::jni::objects::JClass::from_raw(class_ptr as _))
220 }
221 }
222
223 $(
224 pub fn new(env: &mut $crate::jni::JNIEnv $(, $ctor_arg : impl $crate::IsA<$ctor_arg_ty>)*) -> Result<Self, $crate::jni::errors::Error> {
225 let class = Self::class(env)?;
226
227 const CTOR_SIG: &str = $crate::export::const_format::concatcp!(
228 "(",
229 $(
230 <$ctor_arg_ty as $crate::JBindingType>::SIGNATURE,
231 )*
232 ")V"
233 );
234
235 static CACHE: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
236
237 let id = CACHE.load(core::sync::atomic::Ordering::Relaxed);
238
239 let mut env_ptr = id >> 32;
240 let mut method_id = id & 0xFFFFFFFF;
241
242 if env_ptr == 0 || env_ptr != env.get_raw() as u64 {
243 env_ptr = env.get_raw() as u64;
244
245 method_id = env.get_method_id(
246 &class,
247 "<init>",
248 CTOR_SIG
249 )?.into_raw() as u64;
250
251 let cache = (env_ptr << 32) | method_id;
252
253 CACHE.store(cache, core::sync::atomic::Ordering::Relaxed);
254 };
255
256 let obj = unsafe{env.new_object_unchecked(
257 class,
258 $crate::jni::objects::JMethodID::from_raw(method_id as _),
259 &[
260 $(
261 <$ctor_arg_ty as $crate::JBindingType>::to_jvalue(unsafe{$crate::IsA::<$ctor_arg_ty>::as_ref(&$ctor_arg)})
262 ),*
263 ]
264 )?};
265
266 let r = env.new_global_ref(obj)?;
267
268 return Ok(Self {
269 _obj: r,
270 });
271 }
272 )?
273
274
275 $(
276 $crate::export::paste::paste!{
277 pub fn [<get_ $field:snake>](&self, env: &mut $crate::jni::JNIEnv) -> Result<$field_ty, $crate::jni::errors::Error>{
278 let class = Self::class(env)?;
279
280 static CACHE: ::core::sync::atomic::AtomicU64 = ::core::sync::atomic::AtomicU64::new(0);
281
282 let id = CACHE.load(::core::sync::atomic::Ordering::Relaxed);
283
284 let mut env_ptr = id >> 32;
285 let mut field_id = id & 0xFFFFFFFF;
286
287 if env_ptr == 0 || env_ptr != env.get_raw() as u64 {
288 env_ptr = env.get_raw() as u64;
289
290 field_id = env.get_field_id(
291 &class,
292 stringify!(u),
293 <i8 as $crate::JReturnType>::SIGNATURE
294 )?.into_raw() as u64;
295
296 let cache = (env_ptr << 32) | field_id;
297
298 CACHE.store(cache, ::core::sync::atomic::Ordering::Relaxed);
299 };
300
301 unsafe{
302 let b = env.get_field_unchecked(
303 self._obj.as_obj(),
304 $crate::jni::objects::JFieldID::from_raw(field_id as _),
305 <$field_ty as $crate::JReturnType>::JNI_RETURN_TY
306 )?;
307
308 return Ok(<$field_ty as $crate::JReturnType>::from_jvalue(env, b.as_jni()))
309 }
310 }
311
312 pub fn [<set_ $field:snake>](&self, env: &mut $crate::jni::JNIEnv, value: $field_ty) -> Result<(), $crate::jni::errors::Error>{
313 let class = Self::class(env)?;
314
315 static CACHE: ::core::sync::atomic::AtomicU64 = ::core::sync::atomic::AtomicU64::new(0);
316
317 let id = CACHE.load(::core::sync::atomic::Ordering::Relaxed);
318
319 let mut env_ptr = id >> 32;
320 let mut field_id = id & 0xFFFFFFFF;
321
322 if env_ptr == 0 || env_ptr != env.get_raw() as u64 {
323 env_ptr = env.get_raw() as u64;
324
325 field_id = env.get_field_id(
326 &class,
327 stringify!(u),
328 <$field_ty as $crate::JReturnType>::SIGNATURE
329 )?.into_raw() as u64;
330
331 let cache = (env_ptr << 32) | field_id;
332
333 CACHE.store(cache, ::core::sync::atomic::Ordering::Relaxed);
334 };
335
336 unsafe{
337 env.set_field_unchecked(
338 self._obj.as_obj(),
339 $crate::jni::objects::JFieldID::from_raw(field_id as _),
340 <$field_ty as $crate::JBindingType>::to_jvalue_ref(&value)
341 )?;
342
343 return Ok(())
344 }
345 }
346 }
347 )*
348
349 $(
350 $crate::export::paste::paste!{
351 pub fn [<$static_method:snake>](env: &mut $crate::jni::JNIEnv $(, $static_arg : impl $crate::IsA<$static_arg_ty>)*) -> Result<$static_ret, $crate::jni::errors::Error>{
352 let class = Self::class(env)?;
353
354 const METHOD_SIG: &str = $crate::export::const_format::concatcp!(
355 "(",
356 $(
357 <$static_arg_ty as $crate::JBindingType>::SIGNATURE,
358 )*
359 ")",
360 <$static_ret as $crate::JReturnType>::SIGNATURE
361 );
362
363 static CACHE: ::core::sync::atomic::AtomicU64 = ::core::sync::atomic::AtomicU64::new(0);
364
365 let id = CACHE.load(::core::sync::atomic::Ordering::Relaxed);
366
367 let mut env_ptr = id >> 32;
368 let mut method_id = id & 0xFFFFFFFF;
369
370 if env_ptr == 0 || env_ptr != env.get_raw() as u64 {
371 env_ptr = env.get_raw() as u64;
372
373 method_id = env.get_static_method_id(
374 &class,
375 stringify!($static_method),
376 METHOD_SIG
377 )?.into_raw() as u64;
378
379 let cache = (env_ptr << 32) | method_id;
380
381 CACHE.store(cache, core::sync::atomic::Ordering::Relaxed);
382 };
383
384 unsafe{
385 let re = env.call_static_method_unchecked(
386 &class,
387 $crate::jni::objects::JStaticMethodID::from_raw(method_id as _),
388 <$static_ret as $crate::JReturnType>::JNI_RETURN_TY,
389 &[
390 $(
391 <$static_arg_ty as $crate::JBindingType>::to_jvalue(unsafe{$crate::IsA::<$static_arg_ty>::as_ref(&$static_arg)})
392 ),*
393 ]
394 )?;
395
396 return Ok(<$static_ret as $crate::JReturnType>::from_jvalue(env, re.as_jni()))
397 };
398 }
399 }
400 )*
401
402 $(
403 $crate::export::paste::paste!{
404 $(#[doc=$doc])*
405 pub fn [<$method:snake>](&self, env: &mut $crate::jni::JNIEnv $(, $arg : impl $crate::IsA<$arg_ty>)*) -> Result<$ret, $crate::jni::errors::Error>{
406 let class = Self::class(env)?;
407
408 const METHOD_SIG: &str = $crate::export::const_format::concatcp!(
409 "(",
410 $(
411 <$arg_ty as $crate::JBindingType>::SIGNATURE,
412 )*
413 ")",
414 <$ret as $crate::JReturnType>::SIGNATURE
415 );
416
417 static CACHE: core::sync::atomic::AtomicU64 = core::sync::atomic::AtomicU64::new(0);
418
419 let id = CACHE.load(core::sync::atomic::Ordering::Relaxed);
420
421 let mut env_ptr = id >> 32;
422 let mut method_id = id & 0xFFFFFFFF;
423
424 if env_ptr == 0 || env_ptr != env.get_raw() as u64 {
425 env_ptr = env.get_raw() as u64;
426
427 method_id = env.get_method_id(
428 &class,
429 stringify!($method),
430 METHOD_SIG
431 )?.into_raw() as u64;
432
433 let cache = (env_ptr << 32) | method_id;
434
435 CACHE.store(cache, core::sync::atomic::Ordering::Relaxed);
436 };
437
438 unsafe{
439 let r = env.call_method_unchecked(
440 self._obj.as_obj(),
441 $crate::jni::objects::JMethodID::from_raw(method_id as _),
442 <$ret as $crate::JReturnType>::JNI_RETURN_TY,
443 &[
444 $(
445 <$arg_ty as $crate::JBindingType>::to_jvalue(unsafe{$crate::IsA::<$arg_ty>::as_ref(&$arg)})
446 ),*
447 ]
448 )?;
449
450 return Ok(<$ret as $crate::JReturnType>::from_jvalue(env, r.as_jni()))
451 };
452 }
453 }
454 )*
455 }
456
457 };
458}
459
460#[macro_export]
461macro_rules! import_interface {
462 (
463 $sig: expr;
464 $name: ident;
465 $(implements $($parent_interface: ty),+;)?
466 $(
467 $(#[doc=$doc:expr])*
468 fn $method:ident (&self $(, $arg:ident : $arg_ty:ty)*) -> $ret:ty;
469 )*
470 ) => {
471 #[repr(transparent)]
472 #[derive(Debug, Clone)]
473 pub struct $name{
474 _obj: $crate::jni::objects::GlobalRef,
475 }
476
477 unsafe impl $crate::JBindingType for $name {
478 const SIGNATURE: &'static str = concat!("L", $sig, ";");
479 const NAME: &'static str = $sig;
480
481 unsafe fn to_jvalue(&self) -> $crate::jni::sys::jvalue {
482 $crate::jni::sys::jvalue{
483 l: self._obj.as_obj().as_raw()
484 }
485 }
486
487 unsafe fn to_jvalue_ref<'obj_ref>(&'obj_ref self) -> $crate::jni::objects::JValue<'_, 'obj_ref>{
488 $crate::jni::objects::JValue::Object(
489 self._obj.as_obj()
490 )
491 }
492 }
493
494 unsafe impl $crate::JReturnType for $name {
495 const SIGNATURE: &'static str = <Self as $crate::JBindingType>::SIGNATURE;
496 const NAME: &'static str = <Self as $crate::JBindingType>::NAME;
497 const JNI_RETURN_TY: jni::signature::ReturnType = jni::signature::ReturnType::Object;
498
499 unsafe fn from_jvalue(env: &mut$crate::JNIEnv, value: $crate::jni::sys::jvalue) -> Self {
500 let o = $crate::jni::objects::JObject::from_raw(value.l);
501 let r = env.new_global_ref(o).expect("failed to create global ref");
502 Self {
503 _obj: r,
504 }
505 }
506 }
507
508 unsafe impl $crate::IsA<$name> for $name{
509 unsafe fn as_ref(&self) -> &$name{
510 self
511 }
512 }
513
514 unsafe impl $crate::IsA<$name> for &$name{
515 unsafe fn as_ref(&self) -> &$name{
516 self
517 }
518 }
519
520 $(
521 $(
522 impl ::core::convert::AsRef<$parent_interface> for $name{
523 fn as_ref(&self) -> &$parent_class{
524 unsafe{
525 core::mem::transmute(self)
526 }
527 }
528 }
529
530 impl From<$name> for $parent_interface{
531 fn from(value: $name) -> $parent_interface{
532 unsafe{
533 core::mem::transmute(value)
534 }
535 }
536 }
537
538 unsafe impl $crate::IsA<$parent_interface> for $name{
539 unsafe fn as_ref(&self) -> &$parent_class{
540 ::core::convert::AsRef::as_ref(self)
541 }
542 }
543
544 unsafe impl $crate::IsA<$parent_interface> for &$name{
545 unsafe fn as_ref(&self) -> &$parent_class{
546 ::core::convert::AsRef::as_ref(self)
547 }
548 }
549 )*
550 )?
551
552 $crate::export::paste::paste!{
553 impl $name{
554 $(
555 $(#[doc=$doc])*
556 pub fn [<$method:snake>](&self, env: &mut $crate::jni::JNIEnv, $($arg: impl $crate::IsA<$arg_ty>),*) -> ::core::result::Result<$ret, $crate::jni::errors::Error>{
557
558 const METHOD_SIG: &str = $crate::export::const_format::concatcp!(
559 "(",
560 $(
561 <$arg_ty as $crate::JBindingType>::SIGNATURE,
562 )*
563 ")",
564 <$ret as $crate::JReturnType>::SIGNATURE
565 );
566
567 let class = env.get_object_class(self._obj.as_obj())?;
568 let method_id = env.get_method_id(class, stringify!($method), METHOD_SIG)?;
569
570 unsafe{
571 let r = env.call_method_unchecked(
572 self._obj.as_obj(),
573 method_id,
574 <$ret as $crate::JReturnType>::JNI_RETURN_TY,
575 &[
576 $(
577 <$arg_ty as $crate::JBindingType>::to_jvalue(unsafe{$crate::IsA::<$arg_ty>::as_ref(&$arg)})
578 ),*
579 ]
580 )?;
581
582 return Ok(<$ret as $crate::JReturnType>::from_jvalue(env, r.as_jni()))
583 };
584 }
585 )*
586 }
587 }
588
589 };
590}