Skip to content

Commit 0eca370

Browse files
committed
shared type binding
1 parent d9b1c86 commit 0eca370

4 files changed

Lines changed: 145 additions & 18 deletions

File tree

zenoh-flat/src/jni_converter.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ impl ReturnForm {
243243
}
244244

245245
impl TypeBinding {
246+
/// Short type name this binding is keyed under (e.g. `"KeyExpr"`).
247+
pub fn name(&self) -> &str {
248+
&self.name
249+
}
250+
246251
pub fn new(name: impl Into<String>) -> Self {
247252
Self {
248253
name: name.into(),
@@ -445,6 +450,20 @@ impl Builder {
445450
self
446451
}
447452

453+
/// Ingest a reusable [`crate::jni_type_binding::JniTypeBinding`]
454+
/// collection. Type bindings, callback decoders, and Kotlin callback
455+
/// names are all merged into the builder; entries in the collection
456+
/// override entries already present in the builder with the same key.
457+
pub fn jni_type_binding(
458+
mut self,
459+
bindings: crate::jni_type_binding::JniTypeBinding,
460+
) -> Self {
461+
self.types.extend(bindings.types);
462+
self.callback_decoders.extend(bindings.callback_decoders);
463+
self.callback_kotlin_types.extend(bindings.callback_kotlin_types);
464+
self
465+
}
466+
448467
/// Path of the function that decodes a `JString` into `String`. Used by
449468
/// the built-in `String` binding.
450469
pub fn string_decoder(mut self, path: impl AsRef<str>) -> Self {

zenoh-flat/src/jni_type_binding.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
//! Reusable collection of JNI type bindings.
2+
//!
3+
//! [`JniTypeBinding`] aggregates a set of [`TypeBinding`]s plus callback
4+
//! registrations into a single value that can be defined once and ingested
5+
//! into many [`crate::jni_converter::Builder`] instances. Useful when a
6+
//! project emits several `JniConverter` outputs (e.g. one per JNI class) that
7+
//! share a common vocabulary of types.
8+
//!
9+
//! ```ignore
10+
//! use zenoh_flat::jni_converter::{ArgDecode, JniConverter, JniForm, TypeBinding};
11+
//! use zenoh_flat::jni_type_binding::JniTypeBinding;
12+
//!
13+
//! let common = JniTypeBinding::new()
14+
//! .type_binding(
15+
//! TypeBinding::new("KeyExpr").consume(
16+
//! JniForm::new(
17+
//! "*const zenoh::key_expr::KeyExpr<'static>",
18+
//! "Long",
19+
//! ArgDecode::ConsumeArc,
20+
//! )
21+
//! .pointer_param(true),
22+
//! ),
23+
//! )
24+
//! .callback_decoder(
25+
//! "Sample",
26+
//! "crate::sample_callback::process_kotlin_sample_callback",
27+
//! "io.zenoh.jni.callbacks.JNISubscriberCallback",
28+
//! );
29+
//!
30+
//! let session_converter = JniConverter::builder()
31+
//! .class_prefix("Java_io_zenoh_jni_JNISessionNative_")
32+
//! .jni_type_binding(common.clone())
33+
//! // ...other builder calls...
34+
//! .build();
35+
//!
36+
//! let publisher_converter = JniConverter::builder()
37+
//! .class_prefix("Java_io_zenoh_jni_JNIPublisherNative_")
38+
//! .jni_type_binding(common)
39+
//! // ...other builder calls...
40+
//! .build();
41+
//! ```
42+
43+
use std::collections::HashMap;
44+
45+
use crate::jni_converter::TypeBinding;
46+
47+
/// Reusable collection of [`TypeBinding`]s and callback registrations.
48+
///
49+
/// Built fluently and consumed by
50+
/// [`crate::jni_converter::Builder::jni_type_binding`]. `Clone` so the same
51+
/// set can be ingested into multiple builders.
52+
#[derive(Default, Clone)]
53+
pub struct JniTypeBinding {
54+
pub(crate) types: HashMap<String, TypeBinding>,
55+
pub(crate) callback_decoders: HashMap<String, syn::Path>,
56+
pub(crate) callback_kotlin_types: HashMap<String, String>,
57+
}
58+
59+
impl JniTypeBinding {
60+
pub fn new() -> Self {
61+
Self::default()
62+
}
63+
64+
/// Add (or replace) a [`TypeBinding`] in this collection.
65+
pub fn type_binding(mut self, binding: TypeBinding) -> Self {
66+
self.types.insert(binding.name().to_string(), binding);
67+
self
68+
}
69+
70+
/// Register a callback decoder. `element_type_name` is the last path
71+
/// segment of the callback's argument type (e.g. `"Sample"`); use
72+
/// `"()"` for zero-arg callbacks. The decoder must have signature
73+
/// `fn(&mut JNIEnv, JObject) -> ZResult<impl Fn(T) + Send + Sync + 'static>`.
74+
pub fn callback_decoder(
75+
mut self,
76+
element_type_name: impl Into<String>,
77+
decoder: impl AsRef<str>,
78+
kotlin_type: impl Into<String>,
79+
) -> Self {
80+
let path: syn::Path = syn::parse_str(decoder.as_ref())
81+
.expect("invalid callback_decoder path");
82+
let name = element_type_name.into();
83+
let kt = kotlin_type.into();
84+
self.callback_decoders.insert(name.clone(), path);
85+
self.callback_kotlin_types.insert(name, kt);
86+
self
87+
}
88+
89+
/// Merge another [`JniTypeBinding`] into this one. Entries in `other`
90+
/// override entries with the same key in `self`.
91+
pub fn merge(mut self, other: JniTypeBinding) -> Self {
92+
self.types.extend(other.types);
93+
self.callback_decoders.extend(other.callback_decoders);
94+
self.callback_kotlin_types.extend(other.callback_kotlin_types);
95+
self
96+
}
97+
}

zenoh-flat/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ pub mod errors;
88
#[cfg(feature = "zenoh-ext")]
99
pub mod ext;
1010
pub mod jni_converter;
11+
pub mod jni_type_binding;
1112
pub mod session;
1213

zenoh-jni/build.rs

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use itertools::Itertools;
22
use zenoh_flat::jni_converter::{ArgDecode, JniForm, ReturnEncode, ReturnForm, TypeBinding};
3+
use zenoh_flat::jni_type_binding::JniTypeBinding;
34

45
fn enum_binding(name: &str, decoder: &str) -> TypeBinding {
56
TypeBinding::new(name).consume(JniForm::new("jni::sys::jint", "Int", ArgDecode::pure(decoder)))
@@ -13,24 +14,12 @@ fn jobject_consume(name: &str, decoder: &str, kotlin: &str) -> TypeBinding {
1314
))
1415
}
1516

16-
fn main() {
17-
let source = prebindgen::Source::new(zenoh_flat::PREBINDGEN_OUT_DIR);
18-
19-
let mut converter = zenoh_flat::jni_converter::JniConverter::builder()
20-
.class_prefix("Java_io_zenoh_jni_JNISessionNative_")
21-
.function_suffix("ViaJNI")
22-
.source_module("zenoh_flat::session")
23-
.struct_source_module("zenoh_flat::ext")
24-
.owned_object("crate::owned_object::OwnedObject")
25-
.zresult("crate::errors::ZResult")
26-
.throw_exception("crate::throw_exception")
27-
.string_decoder("crate::utils::decode_string")
28-
.byte_array_decoder("crate::utils::decode_byte_array")
29-
.kotlin_output("../zenoh-jni/generated-kotlin/io/zenoh/jni/JNISessionNative.kt")
30-
.kotlin_package("io.zenoh.jni")
31-
.kotlin_class("JNISessionNative")
32-
.kotlin_throws("io.zenoh.exceptions.ZError")
33-
.kotlin_init("io.zenoh.ZenohLoad")
17+
/// Type vocabulary shared across every `JniConverter` build in this crate.
18+
/// Defined once and ingested via `Builder::jni_type_binding(...)` so each
19+
/// generated JNI surface (session, publisher, subscriber, ...) sees the same
20+
/// types without duplicating registrations.
21+
fn shared_bindings() -> JniTypeBinding {
22+
JniTypeBinding::new()
3423
.callback_decoder(
3524
"Sample",
3625
"crate::sample_callback::process_kotlin_sample_callback",
@@ -107,6 +96,27 @@ fn main() {
10796
.kotlin("List<ByteArray>"),
10897
),
10998
)
99+
}
100+
101+
fn main() {
102+
let source = prebindgen::Source::new(zenoh_flat::PREBINDGEN_OUT_DIR);
103+
104+
let mut converter = zenoh_flat::jni_converter::JniConverter::builder()
105+
.class_prefix("Java_io_zenoh_jni_JNISessionNative_")
106+
.function_suffix("ViaJNI")
107+
.source_module("zenoh_flat::session")
108+
.struct_source_module("zenoh_flat::ext")
109+
.owned_object("crate::owned_object::OwnedObject")
110+
.zresult("crate::errors::ZResult")
111+
.throw_exception("crate::throw_exception")
112+
.string_decoder("crate::utils::decode_string")
113+
.byte_array_decoder("crate::utils::decode_byte_array")
114+
.kotlin_output("../zenoh-jni/generated-kotlin/io/zenoh/jni/JNISessionNative.kt")
115+
.kotlin_package("io.zenoh.jni")
116+
.kotlin_class("JNISessionNative")
117+
.kotlin_throws("io.zenoh.exceptions.ZError")
118+
.kotlin_init("io.zenoh.ZenohLoad")
119+
.jni_type_binding(shared_bindings())
110120
.build();
111121

112122
let bindings_file =source

0 commit comments

Comments
 (0)