typed_jni/call/
target.rs

1use typed_jni_core::{Arg, JNIEnv, MethodID, StrongRef};
2
3use crate::{LocalObject, ObjectType, TypedRef, builtin::JavaThrowable};
4
5/// A target for a method call.
6///
7/// This trait is implemented for all types that can be the return  of a method call.
8///
9/// Supported Types:
10///
11/// * No return: `()`
12/// * Primitive types: `bool`, `i8`, `u16`, `i32`, `i64`, `f32`, `f64`
13/// * Object types: `LocalObject<Type>`, `Option<LocalObject<Type>>`
14///
15/// # Safety
16///
17/// This trait should not be implemented manually.
18pub unsafe trait Target<'env>: Sized {
19    /// Call a method with a fixed number of arguments.
20    ///
21    /// # Safety
22    ///
23    /// * `args` must match the signature of the `method`.
24    unsafe fn call<const STATIC: bool, const N_ARGS: usize, T: StrongRef>(
25        env: &'env JNIEnv,
26        this: &T,
27        method: MethodID<STATIC>,
28        args: [Arg<'_>; N_ARGS],
29    ) -> Result<Self, LocalObject<'env, JavaThrowable>>;
30
31    /// Call a method with a variable number of arguments.
32    ///
33    /// # Safety
34    ///
35    /// * `args` must match the signature of the `method`.
36    unsafe fn call_variadic<'a, const STATIC: bool, T: StrongRef, Args: IntoIterator<Item = Arg<'a>>>(
37        env: &'env JNIEnv,
38        this: &T,
39        method: MethodID<STATIC>,
40        args: Args,
41    ) -> Result<Self, LocalObject<'env, JavaThrowable>>;
42}
43
44macro_rules! impl_target_for_primitive {
45    ($ty:ty, $call:ident, $call_variadic:ident) => {
46        unsafe impl<'env> Target<'env> for $ty {
47            unsafe fn call<const STATIC: bool, const N_ARGS: usize, T: StrongRef>(
48                env: &'env JNIEnv,
49                this: &T,
50                method: MethodID<STATIC>,
51                args: [Arg<'_>; N_ARGS],
52            ) -> Result<Self, LocalObject<'env, JavaThrowable>> {
53                unsafe { env.$call(this, method, args).map_err(|err| LocalObject::from_ref(err)) }
54            }
55
56            unsafe fn call_variadic<'a, const STATIC: bool, T: StrongRef, Args: IntoIterator<Item = Arg<'a>>>(
57                env: &'env JNIEnv,
58                this: &T,
59                method: MethodID<STATIC>,
60                args: Args,
61            ) -> Result<Self, LocalObject<'env, JavaThrowable>> {
62                unsafe {
63                    env.$call_variadic(this, method, args)
64                        .map_err(|err| LocalObject::from_ref(err))
65                }
66            }
67        }
68    };
69}
70
71impl_target_for_primitive!((), call_void_method, call_void_method_variadic);
72impl_target_for_primitive!(bool, call_boolean_method, call_boolean_method_variadic);
73impl_target_for_primitive!(i8, call_byte_method, call_byte_method_variadic);
74impl_target_for_primitive!(u16, call_char_method, call_char_method_variadic);
75impl_target_for_primitive!(i16, call_short_method, call_short_method_variadic);
76impl_target_for_primitive!(i32, call_int_method, call_int_method_variadic);
77impl_target_for_primitive!(i64, call_long_method, call_long_method_variadic);
78impl_target_for_primitive!(f32, call_float_method, call_float_method_variadic);
79impl_target_for_primitive!(f64, call_double_method, call_double_method_variadic);
80
81macro_rules! impl_target_for_object {
82    ($ty:ty, $ret:ident, $transform:block) => {
83        unsafe impl<'env, Type: ObjectType> Target<'env> for $ty {
84            unsafe fn call<const STATIC: bool, const N_ARGS: usize, T: StrongRef>(
85                env: &'env JNIEnv,
86                this: &T,
87                method: MethodID<STATIC>,
88                args: [Arg<'_>; N_ARGS],
89            ) -> Result<Self, LocalObject<'env, JavaThrowable>> {
90                unsafe {
91                    env.call_object_method(this, method, args)
92                        .map(|$ret| $transform)
93                        .map_err(|err| LocalObject::from_ref(err))
94                }
95            }
96
97            unsafe fn call_variadic<'a, const STATIC: bool, T: StrongRef, Args: IntoIterator<Item = Arg<'a>>>(
98                env: &'env JNIEnv,
99                this: &T,
100                method: MethodID<STATIC>,
101                args: Args,
102            ) -> Result<Self, LocalObject<'env, JavaThrowable>> {
103                unsafe {
104                    env.call_object_method_variadic(this, method, args)
105                        .map(|$ret| $transform)
106                        .map_err(|err| LocalObject::from_ref(err))
107                }
108            }
109        }
110    };
111}
112
113impl_target_for_object!(Option<LocalObject<'env, Type>>, ret, {
114    ret.map(|v| LocalObject::from_ref(v))
115});
116impl_target_for_object!(LocalObject<'env, Type>, ret, {
117    LocalObject::from_ref(ret.expect("call returning null"))
118});
119
120pub struct NewObject<'env, T: ObjectType>(pub LocalObject<'env, T>);
121
122unsafe impl<'env, Type: ObjectType> Target<'env> for NewObject<'env, Type> {
123    unsafe fn call<const STATIC: bool, const N_ARGS: usize, T: StrongRef>(
124        env: &'env JNIEnv,
125        this: &T,
126        method: MethodID<STATIC>, // must be Method<false>
127        args: [Arg<'_>; N_ARGS],
128    ) -> Result<Self, LocalObject<'env, JavaThrowable>> {
129        unsafe {
130            env.new_object(this, core::mem::transmute::<MethodID<STATIC>, MethodID<false>>(method), args)
131                .map(|v| Self(LocalObject::from_ref(v)))
132                .map_err(|err| LocalObject::from_ref(err))
133        }
134    }
135
136    unsafe fn call_variadic<'a, const STATIC: bool, T: StrongRef, Args: IntoIterator<Item = Arg<'a>>>(
137        env: &'env JNIEnv,
138        this: &T,
139        method: MethodID<STATIC>, // must be Method<false>
140        args: Args,
141    ) -> Result<Self, LocalObject<'env, JavaThrowable>> {
142        unsafe {
143            env.new_object_variadic(this, core::mem::transmute::<MethodID<STATIC>, MethodID<false>>(method), args)
144                .map(|v| Self(LocalObject::from_ref(v)))
145                .map_err(|err| LocalObject::from_ref(err))
146        }
147    }
148}