Skip to content

Commit d9b1c86

Browse files
committed
common type binding method
1 parent ddd7bab commit d9b1c86

2 files changed

Lines changed: 92 additions & 131 deletions

File tree

zenoh-flat/src/jni_converter.rs

Lines changed: 41 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,14 @@
4343
//! .throw_exception("crate::throw_exception")
4444
//! .string_decoder("crate::utils::decode_string")
4545
//! .byte_array_decoder("crate::utils::decode_byte_array")
46-
//! .struct_decoder(
47-
//! "KeyExpr",
48-
//! "crate::key_expr::decode_jni_key_expr",
49-
//! "JNIKeyExpr",
46+
//! .type_binding(
47+
//! TypeBinding::new("KeyExpr").kotlin("JNIKeyExpr").consume(
48+
//! JniForm::new(
49+
//! "jni::objects::JObject",
50+
//! "JObject",
51+
//! ArgDecode::env_ref_mut("crate::key_expr::decode_jni_key_expr"),
52+
//! ),
53+
//! ),
5054
//! )
5155
//! .build();
5256
//! source
@@ -111,6 +115,36 @@ pub enum ArgDecode {
111115
ConsumeArc,
112116
}
113117

118+
impl ArgDecode {
119+
/// `ArgDecode::Pure` from a path string (parsed lazily).
120+
pub fn pure(path: impl AsRef<str>) -> Self {
121+
ArgDecode::Pure(syn::parse_str(path.as_ref()).expect("invalid ArgDecode::pure path"))
122+
}
123+
124+
/// `ArgDecode::EnvRefMut` from a path string.
125+
pub fn env_ref_mut(path: impl AsRef<str>) -> Self {
126+
ArgDecode::EnvRefMut(
127+
syn::parse_str(path.as_ref()).expect("invalid ArgDecode::env_ref_mut path"),
128+
)
129+
}
130+
131+
/// `ArgDecode::EnvByVal` from a path string.
132+
pub fn env_by_val(path: impl AsRef<str>) -> Self {
133+
ArgDecode::EnvByVal(
134+
syn::parse_str(path.as_ref()).expect("invalid ArgDecode::env_by_val path"),
135+
)
136+
}
137+
}
138+
139+
impl ReturnEncode {
140+
/// `ReturnEncode::Wrapper` from a path string.
141+
pub fn wrapper(path: impl AsRef<str>) -> Self {
142+
ReturnEncode::Wrapper(
143+
syn::parse_str(path.as_ref()).expect("invalid ReturnEncode::wrapper path"),
144+
)
145+
}
146+
}
147+
114148
/// Clonable closure that produces a TokenStream from the JNI input ident.
115149
#[derive(Clone)]
116150
pub struct InlineFn(Arc<dyn Fn(&syn::Ident) -> TokenStream + Send + Sync>);
@@ -444,62 +478,13 @@ impl Builder {
444478
self
445479
}
446480

447-
/// Register a decoder for an enum type. Equivalent to:
448-
/// ```ignore
449-
/// .type_binding(TypeBinding::new(name)
450-
/// .consume(JniForm::new("jni::sys::jint", "Int", ArgDecode::Pure(<path>))))
451-
/// ```
452-
pub fn enum_decoder(
453-
mut self,
454-
type_name: impl Into<String>,
455-
decoder: impl AsRef<str>,
456-
) -> Self {
457-
let name = type_name.into();
458-
let p: syn::Path =
459-
syn::parse_str(decoder.as_ref()).expect("invalid enum_decoder path");
460-
let binding = self
461-
.types
462-
.entry(name.clone())
463-
.or_insert_with(|| TypeBinding::new(name));
464-
binding.consume = Some(JniForm::new(
465-
"jni::sys::jint",
466-
"Int",
467-
ArgDecode::Pure(p),
468-
));
469-
self
470-
}
471-
472-
/// Register a decoder for a struct parameter passed across JNI as a plain
473-
/// `JObject` (typically a Kotlin data class). The decoder must have
474-
/// signature `fn(&mut JNIEnv, &JObject) -> ZResult<T>`. `kotlin_type` is
475-
/// the Kotlin type name (FQN if out-of-package, bare otherwise).
476-
pub fn struct_decoder(
477-
mut self,
478-
type_name: impl Into<String>,
479-
decoder: impl AsRef<str>,
480-
kotlin_type: impl Into<String>,
481-
) -> Self {
482-
let name = type_name.into();
483-
let kt = kotlin_type.into();
484-
let p: syn::Path =
485-
syn::parse_str(decoder.as_ref()).expect("invalid struct_decoder path");
486-
let binding = self
487-
.types
488-
.entry(name.clone())
489-
.or_insert_with(|| TypeBinding::new(name));
490-
binding.kotlin_type = Some(kt);
491-
binding.consume = Some(JniForm::new(
492-
"jni::objects::JObject",
493-
"JObject",
494-
ArgDecode::EnvRefMut(p),
495-
));
496-
self
497-
}
498-
499481
/// Register a decoder for an `impl Fn(T) + Send + Sync + 'static` callback
500482
/// parameter. `element_type_name` is the last path segment of `T`
501483
/// (e.g. `"Sample"`, `"Query"`, `"Reply"`). The decoder must have
502484
/// signature `fn(&mut JNIEnv, JObject) -> ZResult<impl Fn(T) + Send + Sync + 'static>`.
485+
/// Callbacks have a fundamentally different shape (a closure-builder, not
486+
/// a value decoder) so they are registered separately from
487+
/// [`Builder::type_binding`].
503488
pub fn callback_decoder(
504489
mut self,
505490
element_type_name: impl Into<String>,
@@ -515,56 +500,6 @@ impl Builder {
515500
self
516501
}
517502

518-
/// Register a return-type wrapper for `ZResult<T>` where `T`'s
519-
/// last-segment name equals `type_name`. `wrap_fn` must have signature
520-
/// `fn(&mut JNIEnv, T) -> ZResult<jni_type>`. `default_expr` is the value
521-
/// returned on error (before the exception is thrown on the JVM side).
522-
pub fn return_wrapper(
523-
mut self,
524-
type_name: impl Into<String>,
525-
jni_type: impl AsRef<str>,
526-
wrap_fn: impl AsRef<str>,
527-
default_expr: impl AsRef<str>,
528-
kotlin_type: impl Into<String>,
529-
) -> Self {
530-
let name = type_name.into();
531-
let kt = kotlin_type.into();
532-
let wrap: syn::Path =
533-
syn::parse_str(wrap_fn.as_ref()).expect("invalid return_wrapper wrap_fn path");
534-
let mut form = ReturnForm::new(jni_type, ReturnEncode::Wrapper(wrap), default_expr);
535-
form.kotlin_jni_type = Some(kt);
536-
let binding = self
537-
.types
538-
.entry(name.clone())
539-
.or_insert_with(|| TypeBinding::new(name));
540-
binding.returns = Some(form);
541-
self
542-
}
543-
544-
/// Like [`Builder::return_wrapper`] but applies when `T` is `Vec<E>`
545-
/// with `E`'s last-segment name equal to `element_type_name`.
546-
pub fn return_wrapper_vec(
547-
mut self,
548-
element_type_name: impl Into<String>,
549-
jni_type: impl AsRef<str>,
550-
wrap_fn: impl AsRef<str>,
551-
default_expr: impl AsRef<str>,
552-
kotlin_type: impl Into<String>,
553-
) -> Self {
554-
let name = element_type_name.into();
555-
let kt = kotlin_type.into();
556-
let wrap: syn::Path =
557-
syn::parse_str(wrap_fn.as_ref()).expect("invalid return_wrapper_vec wrap_fn path");
558-
let mut form = ReturnForm::new(jni_type, ReturnEncode::Wrapper(wrap), default_expr);
559-
form.kotlin_jni_type = Some(kt);
560-
let binding = self
561-
.types
562-
.entry(name.clone())
563-
.or_insert_with(|| TypeBinding::new(name));
564-
binding.returns_vec = Some(form);
565-
self
566-
}
567-
568503
/// Enable Kotlin-side prototype generation. `path` is where the `.kt`
569504
/// file will be written when [`JniConverter::write_kotlin`] is called.
570505
pub fn kotlin_output(mut self, path: impl Into<PathBuf>) -> Self {

zenoh-jni/build.rs

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
use itertools::Itertools;
2-
use zenoh_flat::jni_converter::{ArgDecode, JniForm, TypeBinding};
2+
use zenoh_flat::jni_converter::{ArgDecode, JniForm, ReturnEncode, ReturnForm, TypeBinding};
3+
4+
fn enum_binding(name: &str, decoder: &str) -> TypeBinding {
5+
TypeBinding::new(name).consume(JniForm::new("jni::sys::jint", "Int", ArgDecode::pure(decoder)))
6+
}
7+
8+
fn jobject_consume(name: &str, decoder: &str, kotlin: &str) -> TypeBinding {
9+
TypeBinding::new(name).kotlin(kotlin).consume(JniForm::new(
10+
"jni::objects::JObject",
11+
"JObject",
12+
ArgDecode::env_ref_mut(decoder),
13+
))
14+
}
315

416
fn main() {
517
let source = prebindgen::Source::new(zenoh_flat::PREBINDGEN_OUT_DIR);
@@ -19,15 +31,6 @@ fn main() {
1931
.kotlin_class("JNISessionNative")
2032
.kotlin_throws("io.zenoh.exceptions.ZError")
2133
.kotlin_init("io.zenoh.ZenohLoad")
22-
.enum_decoder(
23-
"CongestionControl",
24-
"crate::utils::decode_congestion_control",
25-
)
26-
.enum_decoder("Priority", "crate::utils::decode_priority")
27-
.enum_decoder("Reliability", "crate::utils::decode_reliability")
28-
.enum_decoder("QueryTarget", "crate::utils::decode_query_target")
29-
.enum_decoder("ConsolidationMode", "crate::utils::decode_consolidation")
30-
.enum_decoder("ReplyKeyExpr", "crate::utils::decode_reply_key_expr")
3134
.callback_decoder(
3235
"Sample",
3336
"crate::sample_callback::process_kotlin_sample_callback",
@@ -48,6 +51,24 @@ fn main() {
4851
"crate::sample_callback::process_kotlin_on_close_callback",
4952
"io.zenoh.jni.callbacks.JNIOnCloseCallback",
5053
)
54+
.type_binding(enum_binding(
55+
"CongestionControl",
56+
"crate::utils::decode_congestion_control",
57+
))
58+
.type_binding(enum_binding("Priority", "crate::utils::decode_priority"))
59+
.type_binding(enum_binding("Reliability", "crate::utils::decode_reliability"))
60+
.type_binding(enum_binding(
61+
"QueryTarget",
62+
"crate::utils::decode_query_target",
63+
))
64+
.type_binding(enum_binding(
65+
"ConsolidationMode",
66+
"crate::utils::decode_consolidation",
67+
))
68+
.type_binding(enum_binding(
69+
"ReplyKeyExpr",
70+
"crate::utils::decode_reply_key_expr",
71+
))
5172
// KeyExpr by-value: the JNI side passes `Arc::into_raw(Arc::new(KeyExpr))`
5273
// as a raw pointer; the wrapper reconstructs the Arc, clones the inner
5374
// KeyExpr, and drops the Arc at end of scope. The full path is required
@@ -62,24 +83,29 @@ fn main() {
6283
.pointer_param(true),
6384
),
6485
)
65-
.struct_decoder(
86+
.type_binding(jobject_consume(
6687
"Encoding",
6788
"crate::utils::decode_jni_encoding",
6889
"JNIEncoding",
69-
)
70-
.return_wrapper(
71-
"ZenohId",
72-
"jni::sys::jbyteArray",
73-
"crate::zenoh_id::zenoh_id_to_byte_array",
74-
"jni::objects::JByteArray::default().as_raw()",
75-
"ByteArray",
76-
)
77-
.return_wrapper_vec(
78-
"ZenohId",
79-
"jni::sys::jobject",
80-
"crate::zenoh_id::zenoh_ids_to_java_list",
81-
"jni::objects::JObject::default().as_raw()",
82-
"List<ByteArray>",
90+
))
91+
.type_binding(
92+
TypeBinding::new("ZenohId")
93+
.returns(
94+
ReturnForm::new(
95+
"jni::sys::jbyteArray",
96+
ReturnEncode::wrapper("crate::zenoh_id::zenoh_id_to_byte_array"),
97+
"jni::objects::JByteArray::default().as_raw()",
98+
)
99+
.kotlin("ByteArray"),
100+
)
101+
.returns_vec(
102+
ReturnForm::new(
103+
"jni::sys::jobject",
104+
ReturnEncode::wrapper("crate::zenoh_id::zenoh_ids_to_java_list"),
105+
"jni::objects::JObject::default().as_raw()",
106+
)
107+
.kotlin("List<ByteArray>"),
108+
),
83109
)
84110
.build();
85111

0 commit comments

Comments
 (0)