Skip to content

Commit bc500da

Browse files
committed
ArgDecode enum removed
1 parent 25e72ab commit bc500da

3 files changed

Lines changed: 85 additions & 88 deletions

File tree

zenoh-flat/src/jni_converter.rs

Lines changed: 46 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
9051
impl 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)]
10167
pub 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

137132
impl 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

zenoh-flat/src/jni_type_binding.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@
88
//! [`crate::jni_converter::JniMethodsConverter`] reads it).
99
//!
1010
//! ```ignore
11-
//! use zenoh_flat::jni_converter::{ArgDecode, JniForm, TypeBinding};
11+
//! use zenoh_flat::jni_converter::{InlineFn, JniForm, TypeBinding};
1212
//! use zenoh_flat::jni_type_binding::JniTypeBinding;
13+
//! use quote::quote;
1314
//!
1415
//! let common = JniTypeBinding::new()
1516
//! .type_binding(
1617
//! TypeBinding::new("KeyExpr").consume(
1718
//! JniForm::new(
1819
//! "*const zenoh::key_expr::KeyExpr<'static>",
1920
//! "Long",
20-
//! ArgDecode::ConsumeArc,
21+
//! InlineFn::new(|input| {
22+
//! quote! { (*std::sync::Arc::from_raw(#input)).clone() }
23+
//! }),
2124
//! )
2225
//! .pointer_param(true),
2326
//! ),
@@ -28,7 +31,7 @@ use std::collections::HashMap;
2831

2932
use quote::{quote, ToTokens};
3033

31-
use crate::jni_converter::{ArgDecode, InlineFn, JniForm, ReturnForm};
34+
use crate::jni_converter::{InlineFn, JniForm, ReturnForm};
3235

3336
/// Per-type description of how a Rust type is represented across the JNI
3437
/// boundary. A type may declare up to four forms:
@@ -52,6 +55,11 @@ pub struct TypeBinding {
5255
pub(crate) borrow: Option<JniForm>,
5356
pub(crate) returns: Option<ReturnForm>,
5457
pub(crate) returns_vec: Option<ReturnForm>,
58+
/// Decoder path for Java-enum-shaped types (`fn(jint) -> ZResult<T>`).
59+
/// Set when the type's JNI representation is an `Int` mapped through a
60+
/// pure decoder. Used by struct-field classification to detect enum
61+
/// fields and emit `env.get_field(..., "I")` + decoder call.
62+
pub(crate) enum_decoder: Option<syn::Path>,
5563
}
5664

5765
impl TypeBinding {
@@ -77,6 +85,7 @@ impl TypeBinding {
7785
borrow: None,
7886
returns: None,
7987
returns_vec: None,
88+
enum_decoder: None,
8089
}
8190
}
8291

@@ -85,6 +94,16 @@ impl TypeBinding {
8594
self
8695
}
8796

97+
/// Mark this binding as a Java-enum-shaped type and record the
98+
/// `fn(jint) -> ZResult<T>` decoder path used for both top-level
99+
/// argument decoding and struct-field decoding.
100+
pub fn enum_decoder(mut self, path: impl AsRef<str>) -> Self {
101+
self.enum_decoder = Some(
102+
syn::parse_str(path.as_ref()).expect("invalid TypeBinding::enum_decoder path"),
103+
);
104+
self
105+
}
106+
88107
pub fn consume(mut self, form: JniForm) -> Self {
89108
self.consume = Some(form);
90109
self
@@ -157,7 +176,7 @@ impl JniTypeBinding {
157176
TypeBinding::new("bool").consume(JniForm::new(
158177
"jni::sys::jboolean",
159178
"Boolean",
160-
ArgDecode::Inline(InlineFn::new(|input| quote! { #input != 0 })),
179+
InlineFn::new(|input| quote! { #input != 0 }),
161180
)),
162181
);
163182
// Duration — jlong, inline `Duration::from_millis(x as u64)`.
@@ -166,9 +185,9 @@ impl JniTypeBinding {
166185
TypeBinding::new("Duration").consume(JniForm::new(
167186
"jni::sys::jlong",
168187
"Long",
169-
ArgDecode::Inline(InlineFn::new(|input| {
188+
InlineFn::new(|input| {
170189
quote! { std::time::Duration::from_millis(#input as u64) }
171-
})),
190+
}),
172191
)),
173192
);
174193
self

zenoh-jni/build.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
use itertools::Itertools;
22
use quote::quote;
33
use zenoh_flat::jni_converter::{
4-
ArgDecode, InlineFn, JniForm, JniMethodsConverter, JniStructConverter, ReturnEncode,
5-
ReturnForm, TypeBinding,
4+
InlineFn, JniForm, JniMethodsConverter, JniStructConverter, ReturnEncode, ReturnForm,
5+
TypeBinding,
66
};
77
use zenoh_flat::jni_type_binding::JniTypeBinding;
88

99
fn enum_binding(name: &str, decoder: &str) -> TypeBinding {
10-
TypeBinding::new(name).consume(JniForm::new("jni::sys::jint", "Int", ArgDecode::pure(decoder)))
10+
TypeBinding::new(name)
11+
.enum_decoder(decoder)
12+
.consume(JniForm::new(
13+
"jni::sys::jint",
14+
"Int",
15+
InlineFn::pure(decoder),
16+
))
1117
}
1218

1319
fn jobject_consume(name: &str, decoder: &str, kotlin: &str) -> TypeBinding {
1420
TypeBinding::new(name).kotlin(kotlin).consume(JniForm::new(
1521
"jni::objects::JObject",
1622
"JObject",
17-
ArgDecode::env_ref_mut(decoder),
23+
InlineFn::env_ref_mut(decoder),
1824
))
1925
}
2026

@@ -28,7 +34,7 @@ fn shared_bindings() -> JniTypeBinding {
2834
TypeBinding::new("String").consume(JniForm::new(
2935
"jni::objects::JString",
3036
"String",
31-
ArgDecode::env_ref_mut("crate::utils::decode_string"),
37+
InlineFn::env_ref_mut("crate::utils::decode_string"),
3238
)),
3339
)
3440
// `Vec<u8>` is keyed under the synthetic name "VecU8" — the
@@ -38,7 +44,7 @@ fn shared_bindings() -> JniTypeBinding {
3844
TypeBinding::new("VecU8").consume(JniForm::new(
3945
"jni::objects::JByteArray",
4046
"ByteArray",
41-
ArgDecode::env_ref("crate::utils::decode_byte_array"),
47+
InlineFn::env_ref("crate::utils::decode_byte_array"),
4248
)),
4349
)
4450
.type_binding(jobject_consume(
@@ -88,9 +94,9 @@ fn shared_bindings() -> JniTypeBinding {
8894
JniForm::new(
8995
"*const zenoh::key_expr::KeyExpr<'static>",
9096
"Long",
91-
ArgDecode::Inline(InlineFn::new(|input| {
97+
InlineFn::new(|input| {
9298
quote! { (*std::sync::Arc::from_raw(#input)).clone() }
93-
})),
99+
}),
94100
)
95101
.pointer_param(true),
96102
),

0 commit comments

Comments
 (0)