Skip to content

Commit a9b5eb5

Browse files
committed
decode_field removed
1 parent 8681a26 commit a9b5eb5

3 files changed

Lines changed: 85 additions & 102 deletions

File tree

zenoh-flat/src/jni_converter.rs

Lines changed: 61 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl Default for StructBuilder {
5454
Self {
5555
source_module: syn::parse_str("crate").unwrap(),
5656
zresult: syn::parse_str("ZResult").unwrap(),
57-
types: JniTypeBinding::new(),
57+
types: JniTypeBinding::new().with_builtins(),
5858
}
5959
}
6060
}
@@ -180,53 +180,42 @@ impl JniStructConverter {
180180
let kotlin_fname = snake_to_camel(&fname);
181181
let err_prefix = format!("{struct_name}.{kotlin_fname}: {{}}");
182182

183-
let kind = self.classify_struct_field(&field.ty);
184-
match kind {
185-
StructFieldKind::Bool => {
186-
field_preludes.push(quote! {
187-
let #fname_ident = env.get_field(obj, #kotlin_fname, "Z")
188-
.and_then(|v| v.z())
189-
.map_err(|err| zerror!(#err_prefix, err))?;
190-
});
191-
field_init.push(quote! { #fname_ident });
192-
kotlin_field_lines.push(format!(" val {}: Boolean,", kotlin_fname));
193-
}
194-
StructFieldKind::I64 => {
195-
field_preludes.push(quote! {
196-
let #fname_ident = env.get_field(obj, #kotlin_fname, "J")
197-
.and_then(|v| v.j())
198-
.map_err(|err| zerror!(#err_prefix, err))?;
199-
});
200-
field_init.push(quote! { #fname_ident });
201-
kotlin_field_lines.push(format!(" val {}: Long,", kotlin_fname));
202-
}
203-
StructFieldKind::F64 => {
204-
field_preludes.push(quote! {
205-
let #fname_ident = env.get_field(obj, #kotlin_fname, "D")
206-
.and_then(|v| v.d())
207-
.map_err(|err| zerror!(#err_prefix, err))?;
208-
});
209-
field_init.push(quote! { #fname_ident });
210-
kotlin_field_lines.push(format!(" val {}: Double,", kotlin_fname));
211-
}
212-
StructFieldKind::Enum(decoder) => {
213-
let raw_ident = format_ident!("__{}_raw", fname_ident);
214-
field_preludes.push(quote! {
215-
let #raw_ident = env.get_field(obj, #kotlin_fname, "I")
216-
.and_then(|v| v.i())
217-
.map_err(|err| zerror!(#err_prefix, err))?;
218-
let #fname_ident = #decoder(#raw_ident)?;
219-
});
220-
field_init.push(quote! { #fname_ident });
221-
kotlin_field_lines.push(format!(" val {}: Int,", kotlin_fname));
222-
}
223-
StructFieldKind::Unsupported => panic!(
183+
let binding = self.lookup_struct_field_binding(&field.ty).unwrap_or_else(|| {
184+
panic!(
224185
"unsupported field type `{}` for `{}.{}` at {loc}",
225186
field.ty.to_token_stream(),
226187
struct_name,
227188
fname
228-
),
229-
}
189+
)
190+
});
191+
let (jni_sig, jvalue_method) =
192+
jni_primitive_signature(binding.jni_type()).unwrap_or_else(|| {
193+
panic!(
194+
"field `{}.{}` at {loc}: type `{}` has non-primitive JNI wire form `{}`",
195+
struct_name,
196+
fname,
197+
field.ty.to_token_stream(),
198+
binding.jni_type().to_token_stream()
199+
)
200+
});
201+
let raw_ident = format_ident!("__{}_raw", fname_ident);
202+
let jni_type = binding.jni_type();
203+
let decode_expr = binding
204+
.decode()
205+
.expect("struct-field binding must have a decode")
206+
.call(&raw_ident);
207+
field_preludes.push(quote! {
208+
let #raw_ident: #jni_type = env.get_field(obj, #kotlin_fname, #jni_sig)
209+
.and_then(|v| v.#jvalue_method())
210+
.map_err(|err| zerror!(#err_prefix, err))? as _;
211+
let #fname_ident = #decode_expr;
212+
});
213+
field_init.push(quote! { #fname_ident });
214+
kotlin_field_lines.push(format!(
215+
" val {}: {},",
216+
kotlin_fname,
217+
binding.kotlin_type()
218+
));
230219
}
231220

232221
let tokens = quote! {
@@ -261,28 +250,15 @@ impl JniStructConverter {
261250
syn::parse2(tokens).expect("generated struct decoder must parse")
262251
}
263252

264-
/// Classify a `#[prebindgen]` struct field's type for JNI round-tripping.
265-
fn classify_struct_field(&self, ty: &syn::Type) -> StructFieldKind {
266-
let syn::Type::Path(tp) = ty else {
267-
return StructFieldKind::Unsupported;
268-
};
269-
let Some(last) = tp.path.segments.last() else {
270-
return StructFieldKind::Unsupported;
271-
};
253+
/// Look up a `#[prebindgen]` struct field's type in the registry. Fields
254+
/// must use the type's bare path-tail name (e.g. `bool`, `i64`,
255+
/// `CongestionControl`) and must resolve to a registered binding whose
256+
/// JNI wire form is one of the primitive `j*` types.
257+
fn lookup_struct_field_binding(&self, ty: &syn::Type) -> Option<&TypeBinding> {
258+
let syn::Type::Path(tp) = ty else { return None };
259+
let last = tp.path.segments.last()?;
272260
let name = last.ident.to_string();
273-
match name.as_str() {
274-
"bool" => StructFieldKind::Bool,
275-
"i64" => StructFieldKind::I64,
276-
"f64" => StructFieldKind::F64,
277-
_ => {
278-
if let Some(binding) = self.cfg.types.types.get(&name) {
279-
if let Some(p) = binding.enum_field_decoder_path() {
280-
return StructFieldKind::Enum(p.clone());
281-
}
282-
}
283-
StructFieldKind::Unsupported
284-
}
285-
}
261+
self.cfg.types.types.get(&name)
286262
}
287263
}
288264

@@ -800,13 +776,26 @@ impl JniMethodsConverter {
800776
// Internal helpers
801777
// =====================================================================
802778

803-
/// Field-type classification for `#[prebindgen]` struct fields.
804-
enum StructFieldKind {
805-
Bool,
806-
I64,
807-
F64,
808-
Enum(syn::Path),
809-
Unsupported,
779+
/// Map a primitive JNI wire type (`jni::sys::j*`) to the JVM field
780+
/// signature character and the matching `JValue` accessor method.
781+
/// Returns `None` for non-primitive (object-shaped) wire types.
782+
fn jni_primitive_signature(jni_type: &syn::Type) -> Option<(&'static str, syn::Ident)> {
783+
let syn::Type::Path(tp) = jni_type else {
784+
return None;
785+
};
786+
let last = tp.path.segments.last()?;
787+
let (sig, accessor) = match last.ident.to_string().as_str() {
788+
"jboolean" => ("Z", "z"),
789+
"jbyte" => ("B", "b"),
790+
"jchar" => ("C", "c"),
791+
"jshort" => ("S", "s"),
792+
"jint" => ("I", "i"),
793+
"jlong" => ("J", "j"),
794+
"jfloat" => ("F", "f"),
795+
"jdouble" => ("D", "d"),
796+
_ => return None,
797+
};
798+
Some((sig, format_ident!("{}", accessor)))
810799
}
811800

812801
fn is_unit(ty: &syn::Type) -> bool {

zenoh-flat/src/jni_type_binding.rs

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
//! * `jni_type` — the on-the-wire JNI type emitted in the wrapper signature
1212
//! * `decode` — JNI value → Rust value (param-direction rows)
1313
//! * `encode` + `default_expr` — Rust value → JNI value (return-direction rows)
14-
//! * `enum_field_decoder` — only for enum-shaped rows, used by struct-field
15-
//! classification
1614
//!
1715
//! Wrapper types (`&T`, `Vec<T>`, `Option<T>`, `ZResult<T>`) are **not**
1816
//! decomposed by the classifier — each must have its own explicit row. The
@@ -108,10 +106,6 @@ pub struct TypeBinding {
108106
/// Default JNI value emitted on the throw-return path. Required when
109107
/// `encode` is set.
110108
pub(crate) default_expr: Option<syn::Expr>,
111-
/// Decoder path for Java-enum-shaped types (`fn(jint) -> ZResult<T>`).
112-
/// Used by struct-field classification to detect enum fields and emit
113-
/// `env.get_field(..., "I")` + decoder call.
114-
pub(crate) enum_field_decoder: Option<syn::Path>,
115109
}
116110

117111
impl TypeBinding {
@@ -129,7 +123,6 @@ impl TypeBinding {
129123
decode: Some(decode),
130124
encode: None,
131125
default_expr: None,
132-
enum_field_decoder: None,
133126
}
134127
}
135128

@@ -151,20 +144,9 @@ impl TypeBinding {
151144
syn::parse_str(default_expr.as_ref())
152145
.expect("invalid TypeBinding::returns default_expr"),
153146
),
154-
enum_field_decoder: None,
155147
}
156148
}
157149

158-
/// Mark this binding as a Java-enum-shaped type. Used by struct-field
159-
/// classification to emit `env.get_field(..., "I")` + `<path>(raw)?`.
160-
pub fn enum_field_decoder(mut self, path: impl AsRef<str>) -> Self {
161-
self.enum_field_decoder = Some(
162-
syn::parse_str(path.as_ref())
163-
.expect("invalid TypeBinding::enum_field_decoder path"),
164-
);
165-
self
166-
}
167-
168150
/// Convenience: opaque borrow `&T` — JNI side passes raw `*const T`,
169151
/// decoded via `<owned_object>::from_raw`. Because the row's key starts
170152
/// with `&`, the wrapped fn receives `&name` automatically.
@@ -228,7 +210,6 @@ impl TypeBinding {
228210
})),
229211
encode: None,
230212
default_expr: None,
231-
enum_field_decoder: None,
232213
}
233214
}
234215

@@ -252,9 +233,6 @@ impl TypeBinding {
252233
pub(crate) fn default_expr(&self) -> Option<&syn::Expr> {
253234
self.default_expr.as_ref()
254235
}
255-
pub(crate) fn enum_field_decoder_path(&self) -> Option<&syn::Path> {
256-
self.enum_field_decoder.as_ref()
257-
}
258236
/// `&T` row — wrapped fn receives `&name`.
259237
pub(crate) fn is_borrow(&self) -> bool {
260238
self.rust_type.starts_with('&')
@@ -306,8 +284,8 @@ impl JniTypeBinding {
306284
}
307285

308286
/// Pre-register built-in language types whose JNI form is fully described
309-
/// without any project-specific decoder path: `bool` (inline `x != 0`)
310-
/// and `Duration` (inline `Duration::from_millis(x as u64)`).
287+
/// without any project-specific decoder path: `bool`, `i64`, `f64`, and
288+
/// `Duration`.
311289
pub fn with_builtins(mut self) -> Self {
312290
let bool_row = TypeBinding::param(
313291
"bool",
@@ -317,6 +295,22 @@ impl JniTypeBinding {
317295
);
318296
self.types.insert(bool_row.rust_type.clone(), bool_row);
319297

298+
let i64_row = TypeBinding::param(
299+
"i64",
300+
"Long",
301+
"jni::sys::jlong",
302+
InlineFn::new(|input| quote! { #input }),
303+
);
304+
self.types.insert(i64_row.rust_type.clone(), i64_row);
305+
306+
let f64_row = TypeBinding::param(
307+
"f64",
308+
"Double",
309+
"jni::sys::jdouble",
310+
InlineFn::new(|input| quote! { #input }),
311+
);
312+
self.types.insert(f64_row.rust_type.clone(), f64_row);
313+
320314
let duration_row = TypeBinding::param(
321315
"Duration",
322316
"Long",

zenoh-jni/build.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,37 +56,37 @@ fn shared_bindings() -> JniTypeBinding {
5656
"Int",
5757
"jni::sys::jint",
5858
InlineFn::pure("crate::utils::decode_congestion_control"),
59-
).enum_field_decoder("crate::utils::decode_congestion_control"))
59+
))
6060
.type_binding(TypeBinding::param(
6161
"Priority",
6262
"Int",
6363
"jni::sys::jint",
6464
InlineFn::pure("crate::utils::decode_priority"),
65-
).enum_field_decoder("crate::utils::decode_priority"))
65+
))
6666
.type_binding(TypeBinding::param(
6767
"Reliability",
6868
"Int",
6969
"jni::sys::jint",
7070
InlineFn::pure("crate::utils::decode_reliability"),
71-
).enum_field_decoder("crate::utils::decode_reliability"))
71+
))
7272
.type_binding(TypeBinding::param(
7373
"QueryTarget",
7474
"Int",
7575
"jni::sys::jint",
7676
InlineFn::pure("crate::utils::decode_query_target"),
77-
).enum_field_decoder("crate::utils::decode_query_target"))
77+
))
7878
.type_binding(TypeBinding::param(
7979
"ConsolidationMode",
8080
"Int",
8181
"jni::sys::jint",
8282
InlineFn::pure("crate::utils::decode_consolidation"),
83-
).enum_field_decoder("crate::utils::decode_consolidation"))
83+
))
8484
.type_binding(TypeBinding::param(
8585
"ReplyKeyExpr",
8686
"Int",
8787
"jni::sys::jint",
8888
InlineFn::pure("crate::utils::decode_reply_key_expr"),
89-
).enum_field_decoder("crate::utils::decode_reply_key_expr"))
89+
))
9090
// KeyExpr by-value: JNI side passes `Arc::into_raw(Arc::new(KeyExpr))`
9191
// as a raw pointer; the wrapper reconstructs the Arc, clones the inner
9292
// KeyExpr, and drops the Arc at end of scope. The full path is required

0 commit comments

Comments
 (0)