jni_bind/
lib.rs

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
17/// this trait should only be implemented by macro.
18/// Manually implementing this trait may cause undefined behaviour
19pub 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
42/// this trait should only be implemented by macro,
43/// manually implement this trait will cause undefined behaviour
44pub 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}