typed_jni/call/
args.rs

1use typed_jni_core::{Arg, JNIEnv, MethodID, StrongRef};
2
3use crate::{LocalObject, Null, Object, ObjectType, Signature, Type, builtin::JavaThrowable, call::target::Target};
4
5/// Converts a value to a JNI call argument.
6///
7/// Supported Types:
8/// - Primitives: `bool`, `i8`, `u16`, `i16`, `i32`, `i64`, `f32`, `f64`
9/// - Any [Object] with [`StrongRef`]: `Object<impl StrongRef, Type>`, `Option<Object<impl StrongRef, Type>>`
10/// - Any reference to [Object] with [`StrongRef`]: `&Object<impl StrongRef, Type>`, `Option<&Object<impl StrongRef, Type>>`
11pub trait ToArg {
12    fn to_arg(&self) -> Arg<'_>;
13}
14
15macro_rules! impl_to_arg_primitive {
16    ($t:ty, $variant:ident) => {
17        impl ToArg for $t {
18            fn to_arg(&self) -> Arg<'_> {
19                Arg::$variant(*self)
20            }
21        }
22    };
23}
24
25impl_to_arg_primitive!(bool, Boolean);
26impl_to_arg_primitive!(i8, Byte);
27impl_to_arg_primitive!(u16, Char);
28impl_to_arg_primitive!(i16, Short);
29impl_to_arg_primitive!(i32, Int);
30impl_to_arg_primitive!(i64, Long);
31impl_to_arg_primitive!(f32, Float);
32impl_to_arg_primitive!(f64, Double);
33
34impl<R: StrongRef, T: ObjectType> ToArg for Object<R, T> {
35    fn to_arg(&self) -> Arg<'_> {
36        Arg::Object(Some(&**self))
37    }
38}
39
40impl<R: StrongRef, T: ObjectType> ToArg for Option<Object<R, T>> {
41    fn to_arg(&self) -> Arg<'_> {
42        match self {
43            Some(obj) => Arg::Object(Some(&**obj)),
44            None => Arg::Object(None),
45        }
46    }
47}
48
49impl<R: StrongRef, T: ObjectType> ToArg for &Object<R, T> {
50    fn to_arg(&self) -> Arg<'_> {
51        Arg::Object(Some(&***self))
52    }
53}
54
55impl<R: StrongRef, T: ObjectType> ToArg for Option<&Object<R, T>> {
56    fn to_arg(&self) -> Arg<'_> {
57        match self {
58            Some(obj) => Arg::Object(Some(&***obj)),
59            None => Arg::Object(None),
60        }
61    }
62}
63
64impl<T: ObjectType> ToArg for Null<T> {
65    fn to_arg(&self) -> Arg<'_> {
66        Arg::Object(None)
67    }
68}
69
70/// Args to be applied to a JNI call.
71///
72/// # Safety
73///
74/// The implementer must ensure that the `signature` matches the signature of the arguments.
75pub unsafe trait Args: Sized {
76    fn signature(&self) -> impl IntoIterator<Item = Signature> + Clone + '_;
77
78    /// Apply the arguments to a JNI call.
79    ///
80    /// # Safety
81    ///
82    /// The implementer must ensure that the `signature` matches the signature of the arguments.
83    unsafe fn apply_on<'env, const STATIC: bool, T, R>(
84        self,
85        env: &'env JNIEnv,
86        this: &T,
87        method: MethodID<STATIC>,
88    ) -> Result<R, LocalObject<'env, JavaThrowable>>
89    where
90        T: StrongRef,
91        R: Target<'env>;
92}
93
94unsafe impl Args for () {
95    fn signature(&self) -> impl IntoIterator<Item = Signature> + Clone + '_ {
96        []
97    }
98
99    unsafe fn apply_on<'env, const STATIC: bool, T, R>(
100        self,
101        env: &'env JNIEnv,
102        this: &T,
103        method: MethodID<STATIC>,
104    ) -> Result<R, LocalObject<'env, JavaThrowable>>
105    where
106        T: StrongRef,
107        R: Target<'env>,
108    {
109        unsafe { R::call(env, this, method, []) }
110    }
111}
112
113macro_rules! impl_fixed_args {
114    ($($n:ident),*) => {
115        unsafe impl<$($n: ToArg + Type),*> Args for ($($n,)*) {
116            fn signature(&self) -> impl IntoIterator<Item = Signature> + Clone + '_ {
117                [$($n::SIGNATURE,)*]
118            }
119
120            unsafe fn apply_on<'env, const STATIC: bool, T, R>(
121                self,
122                env: &'env JNIEnv,
123                this: &T,
124                method: MethodID<STATIC>,
125            ) -> Result<R, LocalObject<'env, JavaThrowable>>
126            where
127                T: StrongRef,
128                R: Target<'env>,
129            {
130                unsafe {
131                    #[allow(non_snake_case)]
132                    let ($($n,)*) = self;
133
134                    R::call(env, this, method, [$($n.to_arg(),)*])
135                }
136            }
137        }
138    };
139}
140
141#[rustfmt::skip]
142const _: () = {
143    impl_fixed_args!(A1);
144    impl_fixed_args!(A1, A2);
145    impl_fixed_args!(A1, A2, A3);
146    impl_fixed_args!(A1, A2, A3, A4);
147    impl_fixed_args!(A1, A2, A3, A4, A5);
148    impl_fixed_args!(A1, A2, A3, A4, A5, A6);
149    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7);
150    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8);
151    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
152    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
153    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
154    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
155    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
156    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
157    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
158    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
159    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
160    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);
161    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
162    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20);
163    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21);
164    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22);
165    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23);
166    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24);
167    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25);
168    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26);
169    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27);
170    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28);
171    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29);
172    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30);
173    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31);
174    impl_fixed_args!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32);
175};
176
177/// A dynamic argument to be applied to a JNI call.
178pub trait DynArg: ToArg {
179    fn signature(&self) -> Signature;
180}
181
182impl<T: Type + ToArg> DynArg for T {
183    fn signature(&self) -> Signature {
184        T::SIGNATURE
185    }
186}
187
188unsafe impl Args for &[&dyn DynArg] {
189    fn signature(&self) -> impl IntoIterator<Item = Signature> + Clone + '_ {
190        self.iter().map(|arg| arg.signature())
191    }
192
193    unsafe fn apply_on<'env, const STATIC: bool, T, R>(
194        self,
195        env: &'env JNIEnv,
196        this: &T,
197        method: MethodID<STATIC>,
198    ) -> Result<R, LocalObject<'env, JavaThrowable>>
199    where
200        T: StrongRef,
201        R: Target<'env>,
202    {
203        unsafe { R::call_variadic(env, this, method, self.iter().map(|arg| arg.to_arg())) }
204    }
205}
206
207unsafe impl<const N: usize> Args for [&dyn DynArg; N] {
208    fn signature(&self) -> impl IntoIterator<Item = Signature> + Clone + '_ {
209        self.map(|arg| arg.signature())
210    }
211
212    unsafe fn apply_on<'env, const STATIC: bool, T, R>(
213        self,
214        env: &'env JNIEnv,
215        this: &T,
216        method: MethodID<STATIC>,
217    ) -> Result<R, LocalObject<'env, JavaThrowable>>
218    where
219        T: StrongRef,
220        R: Target<'env>,
221    {
222        unsafe { R::call(env, this, method, self.map(|arg| arg.to_arg())) }
223    }
224}
225
226unsafe impl<const N: usize> Args for &[&dyn DynArg; N] {
227    fn signature(&self) -> impl IntoIterator<Item = Signature> + Clone + '_ {
228        (*self).signature()
229    }
230
231    unsafe fn apply_on<'env, const STATIC: bool, T, R>(
232        self,
233        env: &'env JNIEnv,
234        this: &T,
235        method: MethodID<STATIC>,
236    ) -> Result<R, LocalObject<'env, JavaThrowable>>
237    where
238        T: StrongRef,
239        R: Target<'env>,
240    {
241        unsafe { (*self).apply_on(env, this, method) }
242    }
243}