@@ -48,45 +48,6 @@ pub use crate::jni_type_binding::TypeBinding;
4848// Decode / encode strategies
4949// =====================================================================
5050
51- /// Strategy for converting a JNI parameter into a Rust value.
52- #[ derive( Clone ) ]
53- pub enum ArgDecode {
54- /// `let <name> = <path>(&mut env, &<input>)?;` — for decoders that need
55- /// mutable access to the JNI environment (e.g. `JNIEnv::get_string`).
56- EnvRefMut ( syn:: Path ) ,
57- /// `let <name> = <path>(&env, &<input>)?;` — for decoders that only
58- /// need shared access to the JNI environment (e.g. byte-array readers
59- /// whose `JNIEnv` methods take `&self`).
60- EnvRef ( syn:: Path ) ,
61- /// `let <name> = <path>(<input>)?;` — pure conversion (e.g. enum decoders).
62- Pure ( syn:: Path ) ,
63- /// `let <name> = <expr>;` — inline transformation built from the input
64- /// ident. Used for trivial conversions like `bool` (`x != 0`) or
65- /// `Duration` (`Duration::from_millis(x as u64)`).
66- Inline ( InlineFn ) ,
67- }
68-
69- impl ArgDecode {
70- /// `ArgDecode::Pure` from a path string (parsed lazily).
71- pub fn pure ( path : impl AsRef < str > ) -> Self {
72- ArgDecode :: Pure ( syn:: parse_str ( path. as_ref ( ) ) . expect ( "invalid ArgDecode::pure path" ) )
73- }
74-
75- /// `ArgDecode::EnvRefMut` from a path string.
76- pub fn env_ref_mut ( path : impl AsRef < str > ) -> Self {
77- ArgDecode :: EnvRefMut (
78- syn:: parse_str ( path. as_ref ( ) ) . expect ( "invalid ArgDecode::env_ref_mut path" ) ,
79- )
80- }
81-
82- /// `ArgDecode::EnvRef` from a path string.
83- pub fn env_ref ( path : impl AsRef < str > ) -> Self {
84- ArgDecode :: EnvRef (
85- syn:: parse_str ( path. as_ref ( ) ) . expect ( "invalid ArgDecode::env_ref path" ) ,
86- )
87- }
88- }
89-
9051impl ReturnEncode {
9152 /// `ReturnEncode::Wrapper` from a path string.
9253 pub fn wrapper ( path : impl AsRef < str > ) -> Self {
@@ -97,6 +58,11 @@ impl ReturnEncode {
9758}
9859
9960/// Clonable closure that produces a TokenStream from the JNI input ident.
61+ ///
62+ /// This is the single decoding mechanism used by [`JniForm`]. Common decoder
63+ /// shapes are exposed via [`InlineFn::pure`], [`InlineFn::env_ref`], and
64+ /// [`InlineFn::env_ref_mut`], which capture a decoder path as a `String`
65+ /// (since `syn::Path` is not `Send`) and re-parse it inside the closure.
10066#[ derive( Clone ) ]
10167pub struct InlineFn ( Arc < dyn Fn ( & syn:: Ident ) -> TokenStream + Send + Sync > ) ;
10268
@@ -108,6 +74,35 @@ impl InlineFn {
10874 InlineFn ( Arc :: new ( f) )
10975 }
11076
77+ /// `<path>(<input>)?` — pure conversion (e.g. enum decoders).
78+ pub fn pure ( path : impl AsRef < str > ) -> Self {
79+ let s = path. as_ref ( ) . to_string ( ) ;
80+ InlineFn :: new ( move |input| {
81+ let p: syn:: Path = syn:: parse_str ( & s) . expect ( "invalid InlineFn::pure path" ) ;
82+ quote ! { #p( #input) ? }
83+ } )
84+ }
85+
86+ /// `<path>(&env, &<input>)?` — decoder needing shared access to the JNI env
87+ /// (e.g. byte-array readers whose `JNIEnv` methods take `&self`).
88+ pub fn env_ref ( path : impl AsRef < str > ) -> Self {
89+ let s = path. as_ref ( ) . to_string ( ) ;
90+ InlineFn :: new ( move |input| {
91+ let p: syn:: Path = syn:: parse_str ( & s) . expect ( "invalid InlineFn::env_ref path" ) ;
92+ quote ! { #p( & env, & #input) ? }
93+ } )
94+ }
95+
96+ /// `<path>(&mut env, &<input>)?` — decoder needing mutable access to the
97+ /// JNI env (e.g. `JNIEnv::get_string`).
98+ pub fn env_ref_mut ( path : impl AsRef < str > ) -> Self {
99+ let s = path. as_ref ( ) . to_string ( ) ;
100+ InlineFn :: new ( move |input| {
101+ let p: syn:: Path = syn:: parse_str ( & s) . expect ( "invalid InlineFn::env_ref_mut path" ) ;
102+ quote ! { #p( & mut env, & #input) ? }
103+ } )
104+ }
105+
111106 fn call ( & self , ident : & syn:: Ident ) -> TokenStream {
112107 ( self . 0 ) ( ident)
113108 }
@@ -131,14 +126,14 @@ pub struct JniForm {
131126 /// decoder produces an owner (e.g. `OwnedObject`) but the wrapped
132127 /// function expects a shared reference.
133128 call_with_ref : bool ,
134- decode : ArgDecode ,
129+ decode : InlineFn ,
135130}
136131
137132impl JniForm {
138133 pub fn new (
139134 jni_type : impl AsRef < str > ,
140135 kotlin_jni_type : impl Into < String > ,
141- decode : ArgDecode ,
136+ decode : InlineFn ,
142137 ) -> Self {
143138 Self {
144139 jni_type : syn:: parse_str ( jni_type. as_ref ( ) ) . expect ( "invalid JniForm jni_type" ) ,
@@ -426,14 +421,13 @@ impl JniStructConverter {
426421 }
427422 } ;
428423
429- let decoder_path: syn:: Path = syn:: parse_str ( & format ! ( "decode_{struct_name}" ) )
430- . expect ( "generated decoder ident must parse as path" ) ;
424+ let decoder_path = format ! ( "decode_{struct_name}" ) ;
431425 let mut binding = TypeBinding :: new ( struct_name. clone ( ) ) ;
432426 binding. kotlin_type = Some ( struct_name. clone ( ) ) ;
433427 binding. consume = Some ( JniForm :: new (
434428 "jni::objects::JObject" ,
435429 "JObject" ,
436- ArgDecode :: EnvRefMut ( decoder_path) ,
430+ InlineFn :: env_ref_mut ( & decoder_path) ,
437431 ) ) ;
438432 self . cfg . types . types . insert ( struct_name. clone ( ) , binding) ;
439433
@@ -461,13 +455,9 @@ impl JniStructConverter {
461455 "i64" => StructFieldKind :: I64 ,
462456 "f64" => StructFieldKind :: F64 ,
463457 _ => {
464- // Enum decoders are stored as a `Pure` ArgDecode on the
465- // type's binding's `consume` form.
466458 if let Some ( binding) = self . cfg . types . types . get ( & name) {
467- if let Some ( form) = binding. consume . as_ref ( ) {
468- if let ArgDecode :: Pure ( p) = & form. decode {
469- return StructFieldKind :: Enum ( p. clone ( ) ) ;
470- }
459+ if let Some ( p) = binding. enum_decoder . as_ref ( ) {
460+ return StructFieldKind :: Enum ( p. clone ( ) ) ;
471461 }
472462 }
473463 StructFieldKind :: Unsupported
@@ -1012,11 +1002,11 @@ impl JniMethodsConverter {
10121002 kotlin_jni_type : "Long" . to_string ( ) ,
10131003 pointer_param : true ,
10141004 call_with_ref : true ,
1015- decode : ArgDecode :: Inline ( InlineFn :: new ( move |input| {
1005+ decode : InlineFn :: new ( move |input| {
10161006 let owned: syn:: Path =
10171007 syn:: parse_str ( & owned_str) . expect ( "owned_object must be a valid path" ) ;
10181008 quote ! { #owned:: from_raw( #input) }
1019- } ) ) ,
1009+ } ) ,
10201010 } ;
10211011 ArgKind :: Borrow {
10221012 form : opaque_form,
@@ -1205,21 +1195,8 @@ impl JniMethodsConverter {
12051195 } ;
12061196 jni_params. push ( quote ! { #pat: #jt } ) ;
12071197
1208- match & form. decode {
1209- ArgDecode :: EnvRefMut ( path) => {
1210- prelude. push ( quote ! { let #name = #path( & mut env, & #pat) ?; } ) ;
1211- }
1212- ArgDecode :: EnvRef ( path) => {
1213- prelude. push ( quote ! { let #name = #path( & env, & #pat) ?; } ) ;
1214- }
1215- ArgDecode :: Pure ( path) => {
1216- prelude. push ( quote ! { let #name = #path( #pat) ?; } ) ;
1217- }
1218- ArgDecode :: Inline ( f) => {
1219- let expr = f. call ( & pat) ;
1220- prelude. push ( quote ! { let #name = #expr; } ) ;
1221- }
1222- }
1198+ let expr = form. decode . call ( & pat) ;
1199+ prelude. push ( quote ! { let #name = #expr; } ) ;
12231200
12241201 if form. call_with_ref {
12251202 call_args. push ( quote ! { & #name } ) ;
@@ -1238,13 +1215,8 @@ impl JniMethodsConverter {
12381215 }
12391216 }
12401217
1241- fn decode_expr ( & self , decode : & ArgDecode , input : & syn:: Ident ) -> TokenStream {
1242- match decode {
1243- ArgDecode :: EnvRefMut ( path) => quote ! { #path( & mut env, & #input) ? } ,
1244- ArgDecode :: EnvRef ( path) => quote ! { #path( & env, & #input) ? } ,
1245- ArgDecode :: Pure ( path) => quote ! { #path( #input) ? } ,
1246- ArgDecode :: Inline ( f) => f. call ( input) ,
1247- }
1218+ fn decode_expr ( & self , decode : & InlineFn , input : & syn:: Ident ) -> TokenStream {
1219+ decode. call ( input)
12481220 }
12491221
12501222 /// Resolve the Kotlin parameter type for a JniForm. For object-typed
0 commit comments