diff --git a/.claude/scheduled_tasks.lock b/.claude/scheduled_tasks.lock new file mode 100644 index 00000000..d294f4a9 --- /dev/null +++ b/.claude/scheduled_tasks.lock @@ -0,0 +1 @@ +{"sessionId":"30378df0-b1db-49d0-aaa9-941539dafac8","pid":16376,"procStart":"Thu May 28 10:53:12 2026","acquiredAt":1779977496662} \ No newline at end of file diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index dc5684d9..de7fc4ea 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -78,19 +78,13 @@ tasks { examples.forEach { example -> register(example, JavaExec::class) { - dependsOn("CompileZenohJNI") + dependsOn(":zenoh-java:buildZenohFlatJni") description = "Run the $example example" mainClass.set("io.zenoh.$example") classpath(sourceSets["main"].runtimeClasspath) - val zenohPaths = "../zenoh-jni/target/release" + val zenohPaths = "../zenoh-flat-jni/target/release" val defaultJvmArgs = arrayListOf("-Djava.library.path=$zenohPaths") jvmArgs(defaultJvmArgs) } } } - -tasks.register("CompileZenohJNI") { - project.exec { - commandLine("cargo", "build", "--release", "--manifest-path", "../zenoh-jni/Cargo.toml") - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 2d17a6a4..1163fec9 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -23,7 +23,7 @@ rootProject.name = "zenoh-java" include(":zenoh-java") include(":examples") -include(":zenoh-jni") +include(":zenoh-flat-jni") plugins { id("org.gradle.toolchains.foojay-resolver-convention") version("0.4.0") diff --git a/zenoh-jni/Cargo.lock b/zenoh-flat-jni/Cargo.lock similarity index 91% rename from zenoh-jni/Cargo.lock rename to zenoh-flat-jni/Cargo.lock index d2aa6546..5bc58a1f 100644 --- a/zenoh-jni/Cargo.lock +++ b/zenoh-flat-jni/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "adler2" @@ -97,9 +97,9 @@ checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" [[package]] name = "asn1-rs" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -134,12 +134,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "async-std" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" - [[package]] name = "async-trait" version = "0.1.89" @@ -151,22 +145,11 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "base64" @@ -189,6 +172,15 @@ dependencies = [ "serde", ] +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -197,9 +189,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" dependencies = [ "serde_core", ] @@ -213,11 +205,20 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "byteorder" @@ -233,9 +234,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cc" -version = "1.2.59" +version = "1.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a4d3ec6524d28a329fc53654bbadc9bdd7b0431f5d65f1a56ffb28a1ee5283" +checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" dependencies = [ "find-msvc-tools", "shlex", @@ -281,30 +282,6 @@ dependencies = [ "inout", ] -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex", - "indexmap 1.9.3", - "strsim 0.10.0", - "termcolor", - "textwrap", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - [[package]] name = "combine" version = "4.6.7" @@ -332,11 +309,12 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.35" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" dependencies = [ "const_format_proc_macros", + "konst 0.2.20", ] [[package]] @@ -350,6 +328,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "const_panic" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e262cdaac42494e3ae34c43969f9cdeb7da178bdb4b66fa6a1ea2edb4c8ae652" +dependencies = [ + "typewit", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -469,7 +456,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.11.1", + "strsim", "syn 2.0.117", ] @@ -486,9 +473,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" [[package]] name = "der" @@ -577,9 +564,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "either" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" [[package]] name = "env_logger" @@ -616,7 +603,7 @@ checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" dependencies = [ "getrandom 0.3.4", "libm", - "rand 0.9.2", + "rand 0.9.4", "siphasher", ] @@ -648,19 +635,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "flume" -version = "0.10.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" -dependencies = [ - "futures-core", - "futures-sink", - "nanorand", - "pin-project", - "spin 0.9.8", -] - [[package]] name = "flume" version = "0.11.1" @@ -889,19 +863,16 @@ dependencies = [ ] [[package]] -name = "heck" -version = "0.5.0" +name = "hashbrown" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -1086,14 +1057,20 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" dependencies = [ "icu_normalizer", "icu_properties", ] +[[package]] +name = "if_rust_version" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46dbcb333e86939721589d25a3557e180b52778cb33c7fdfe9e0158ff790d5ec" + [[package]] name = "indexmap" version = "1.9.3" @@ -1107,12 +1084,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -1196,10 +1173,12 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.94" +version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" dependencies = [ + "cfg-if", + "futures-util", "once_cell", "wasm-bindgen", ] @@ -1233,6 +1212,48 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97feab15b395d1860944abe6a8dd8ed9f8eadfae01750fada8427abda531d887" +dependencies = [ + "const_panic", + "konst_kernel", + "konst_proc_macros", + "typewit", +] + +[[package]] +name = "konst_kernel" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4b1eb7788f3824c629b1116a7a9060d6e898c358ebff59070093d51103dcc3c" +dependencies = [ + "typewit", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + +[[package]] +name = "konst_proc_macros" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00af7901ba50898c9e545c24d5c580c96a982298134e8037d8978b6594782c07" + [[package]] name = "lazy_static" version = "1.5.0" @@ -1244,9 +1265,9 @@ dependencies = [ [[package]] name = "leb128" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" +checksum = "6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545" [[package]] name = "leb128fmt" @@ -1256,9 +1277,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.184" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libloading" @@ -1278,9 +1299,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ "libc", ] @@ -1378,7 +1399,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "cfg-if", "cfg_aliases", "libc", @@ -1439,16 +1460,16 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand 0.8.5", + "rand 0.8.6", "smallvec", "zeroize", ] [[package]] name = "num-conv" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-integer" @@ -1486,7 +1507,7 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.5.2", + "hermit-abi", "libc", ] @@ -1517,12 +1538,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "os_str_bytes" -version = "6.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" - [[package]] name = "parking" version = "2.2.1" @@ -1634,7 +1649,7 @@ checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", "hashbrown 0.15.5", - "indexmap 2.13.1", + "indexmap 2.14.0", "serde", ] @@ -1681,26 +1696,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project" -version = "1.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", -] - [[package]] name = "pin-project-lite" version = "0.2.17" @@ -1790,6 +1785,38 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prebindgen" +version = "0.4.1" +dependencies = [ + "if_rust_version", + "itertools", + "jni", + "konst 0.3.17", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "roxygen", + "serde", + "serde_json", + "syn 2.0.117", + "toml", +] + +[[package]] +name = "prebindgen-proc-macro" +version = "0.4.1" +dependencies = [ + "prebindgen", + "proc-macro2", + "quote", + "rand 0.9.4", + "serde", + "serde_json", + "syn 2.0.117", +] + [[package]] name = "prettyplease" version = "0.2.37" @@ -1848,7 +1875,7 @@ dependencies = [ "fastbloom", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand 0.9.4", "ring", "rustc-hash", "rustls", @@ -1872,7 +1899,7 @@ dependencies = [ "once_cell", "socket2 0.6.3", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -1898,9 +1925,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -1909,9 +1936,9 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.5", @@ -1957,9 +1984,9 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.14.7" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b99e0098aa4082912d4c649628623db6aba77335e4f4569ff5083a6448b32e" +checksum = "57f6d249aad744e274e682777a50283a225a32705394ee6d5fcc01efa25e4055" dependencies = [ "pem", "ring", @@ -1984,7 +2011,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", ] [[package]] @@ -2077,7 +2104,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4147b952f3f819eca0e99527022f7d6a8d05f111aeb0a62960c74eb283bec8fc" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "once_cell", "serde", "serde_derive", @@ -2085,6 +2112,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "roxygen" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa650dd372f29f0a6be64b2896707f9536962ba28915e3b39bcafd5a6221873b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "rsa" version = "0.9.10" @@ -2131,9 +2169,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" dependencies = [ "log", "once_cell", @@ -2167,9 +2205,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.0" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" dependencies = [ "web-time", "zeroize", @@ -2204,9 +2242,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "ring", "rustls-pki-types", @@ -2303,7 +2341,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "core-foundation", "core-foundation-sys", "libc", @@ -2369,9 +2407,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", @@ -2391,15 +2429,16 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.18.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" +checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" dependencies = [ "base64", + "bs58", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.13.1", + "indexmap 2.14.0", "schemars 0.9.0", "schemars 1.2.1", "serde_core", @@ -2410,9 +2449,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.18.0" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" +checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" dependencies = [ "darling", "proc-macro2", @@ -2426,7 +2465,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.13.1", + "indexmap 2.14.0", "itoa", "ryu", "serde", @@ -2463,9 +2502,9 @@ checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" [[package]] name = "sha3" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" dependencies = [ "digest", "keccak", @@ -2513,9 +2552,9 @@ checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "siphasher" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" [[package]] name = "slab" @@ -2605,7 +2644,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "rand 0.8.5", + "rand 0.8.6", "syn 1.0.109", ] @@ -2621,12 +2660,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.1" @@ -2672,21 +2705,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" - [[package]] name = "thiserror" version = "1.0.69" @@ -2818,9 +2836,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.51.0" +version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bd1c4c0fc4a7ab90fc15ef6daaa3ec3b893f004f915f2392557ed23237820cd" +checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", "libc", @@ -2884,7 +2902,7 @@ version = "0.9.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" dependencies = [ - "indexmap 2.13.1", + "indexmap 2.14.0", "serde_core", "serde_spanned", "toml_datetime 0.7.5+spec-1.1.0", @@ -2917,10 +2935,10 @@ version = "0.25.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ - "indexmap 2.13.1", + "indexmap 2.14.0", "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow 1.0.1", + "winnow 1.0.3", ] [[package]] @@ -2929,7 +2947,7 @@ version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "winnow 1.0.1", + "winnow 1.0.3", ] [[package]] @@ -3025,7 +3043,7 @@ dependencies = [ "http", "httparse", "log", - "rand 0.8.5", + "rand 0.8.6", "sha1", "thiserror 1.0.69", "utf-8", @@ -3049,9 +3067,24 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" + +[[package]] +name = "typewit" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "214ca0b2191785cbc06209b9ca1861e048e39b5ba33574b3cedd58363d5bb5f6" +dependencies = [ + "typewit_proc_macros", +] + +[[package]] +name = "typewit_proc_macros" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36a83ea2b3c704935a01b4642946aadd445cea40b10935e3f8bd8052b8193d6" [[package]] name = "ucd-trie" @@ -3068,7 +3101,7 @@ dependencies = [ "humantime", "lazy_static", "log", - "rand 0.8.5", + "rand 0.8.6", "serde", "spin 0.10.0", ] @@ -3134,9 +3167,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -3203,11 +3236,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", ] [[package]] @@ -3216,14 +3249,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.117" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" dependencies = [ "cfg-if", "once_cell", @@ -3234,9 +3267,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.117" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3244,9 +3277,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.117" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" dependencies = [ "bumpalo", "proc-macro2", @@ -3257,9 +3290,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.117" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" dependencies = [ "unicode-ident", ] @@ -3281,7 +3314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap 2.13.1", + "indexmap 2.14.0", "wasm-encoder", "wasmparser", ] @@ -3292,9 +3325,9 @@ version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "bitflags 2.11.0", + "bitflags 2.11.1", "hashbrown 0.15.5", - "indexmap 2.13.1", + "indexmap 2.14.0", "semver", ] @@ -3310,18 +3343,18 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" dependencies = [ "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" dependencies = [ "rustls-pki-types", ] @@ -3434,15 +3467,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - [[package]] name = "windows-sys" version = "0.61.2" @@ -3476,30 +3500,13 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", + "windows_i686_gnullvm", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -3512,12 +3519,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -3530,12 +3531,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -3548,24 +3543,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -3578,12 +3561,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -3596,12 +3573,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -3614,12 +3585,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -3632,12 +3597,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" version = "0.7.15" @@ -3646,9 +3605,9 @@ checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" [[package]] name = "winnow" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" +checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" dependencies = [ "memchr", ] @@ -3662,6 +3621,12 @@ dependencies = [ "wit-bindgen-rust-macro", ] +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "wit-bindgen-core" version = "0.51.0" @@ -3681,7 +3646,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", - "indexmap 2.13.1", + "indexmap 2.14.0", "prettyplease", "syn 2.0.117", "wasm-metadata", @@ -3711,8 +3676,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", - "bitflags 2.11.0", - "indexmap 2.13.1", + "bitflags 2.11.1", + "indexmap 2.14.0", "log", "serde", "serde_derive", @@ -3731,7 +3696,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap 2.13.1", + "indexmap 2.14.0", "log", "semver", "serde", @@ -3767,10 +3732,11 @@ dependencies = [ [[package]] name = "yasna" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec", "time", ] @@ -3800,7 +3766,7 @@ dependencies = [ [[package]] name = "zenoh" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "ahash", "arc-swap", @@ -3808,7 +3774,7 @@ dependencies = [ "bytes", "const_format", "flate2", - "flume 0.11.1", + "flume", "futures", "git-version", "itertools", @@ -3818,7 +3784,7 @@ dependencies = [ "once_cell", "petgraph", "phf", - "rand 0.8.5", + "rand 0.8.6", "rustc_version", "serde", "serde_json", @@ -3850,7 +3816,7 @@ dependencies = [ [[package]] name = "zenoh-buffers" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "zenoh-collections", ] @@ -3858,7 +3824,7 @@ dependencies = [ [[package]] name = "zenoh-codec" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "tracing", "uhlc", @@ -3869,7 +3835,7 @@ dependencies = [ [[package]] name = "zenoh-collections" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "ahash", ] @@ -3877,7 +3843,7 @@ dependencies = [ [[package]] name = "zenoh-config" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "json5", "nonempty-collections", @@ -3902,7 +3868,7 @@ dependencies = [ [[package]] name = "zenoh-core" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "lazy_static", "tokio", @@ -3913,11 +3879,11 @@ dependencies = [ [[package]] name = "zenoh-crypto" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "aes", "hmac", - "rand 0.8.5", + "rand 0.8.6", "rand_chacha 0.3.1", "sha3", "zenoh-result", @@ -3926,11 +3892,11 @@ dependencies = [ [[package]] name = "zenoh-ext" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "bincode", - "flume 0.11.1", + "flume", "futures", "leb128", "serde", @@ -3942,15 +3908,42 @@ dependencies = [ "zenoh-util", ] +[[package]] +name = "zenoh-flat" +version = "1.9.0" +dependencies = [ + "android-logd-logger", + "json5", + "prebindgen", + "prebindgen-proc-macro", + "serde_yaml", + "tracing", + "zenoh", +] + +[[package]] +name = "zenoh-flat-jni" +version = "0.1.0" +dependencies = [ + "jni", + "konst 0.3.17", + "prebindgen", + "syn 2.0.117", + "tracing", + "zenoh", + "zenoh-ext", + "zenoh-flat", +] + [[package]] name = "zenoh-keyexpr" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "getrandom 0.2.17", "hashbrown 0.16.1", "keyed-set", - "rand 0.8.5", + "rand 0.8.6", "schemars 1.2.1", "serde", "token-cell", @@ -3960,7 +3953,7 @@ dependencies = [ [[package]] name = "zenoh-link" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "zenoh-config", "zenoh-link-commons", @@ -3978,12 +3971,12 @@ dependencies = [ [[package]] name = "zenoh-link-commons" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "base64", "bytes", - "flume 0.11.1", + "flume", "futures", "quinn", "quinn-proto", @@ -4014,7 +4007,7 @@ dependencies = [ [[package]] name = "zenoh-link-quic" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "rustls-webpki", @@ -4030,7 +4023,7 @@ dependencies = [ [[package]] name = "zenoh-link-quic_datagram" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "rustls-webpki", @@ -4046,7 +4039,7 @@ dependencies = [ [[package]] name = "zenoh-link-tcp" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "socket2 0.5.10", @@ -4063,7 +4056,7 @@ dependencies = [ [[package]] name = "zenoh-link-tls" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "base64", @@ -4092,7 +4085,7 @@ dependencies = [ [[package]] name = "zenoh-link-udp" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "libc", @@ -4114,7 +4107,7 @@ dependencies = [ [[package]] name = "zenoh-link-unixsock_stream" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "nix", @@ -4132,7 +4125,7 @@ dependencies = [ [[package]] name = "zenoh-link-ws" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "futures-util", @@ -4152,7 +4145,7 @@ dependencies = [ [[package]] name = "zenoh-macros" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "proc-macro2", "quote", @@ -4163,7 +4156,7 @@ dependencies = [ [[package]] name = "zenoh-plugin-trait" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "git-version", "libloading", @@ -4180,10 +4173,10 @@ dependencies = [ [[package]] name = "zenoh-protocol" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "const_format", - "rand 0.8.5", + "rand 0.8.6", "serde", "uhlc", "zenoh-buffers", @@ -4195,7 +4188,7 @@ dependencies = [ [[package]] name = "zenoh-result" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "anyhow", ] @@ -4203,7 +4196,7 @@ dependencies = [ [[package]] name = "zenoh-runtime" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "lazy_static", "ron", @@ -4217,7 +4210,7 @@ dependencies = [ [[package]] name = "zenoh-sync" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "arc-swap", "event-listener", @@ -4231,7 +4224,7 @@ dependencies = [ [[package]] name = "zenoh-task" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "futures", "tokio", @@ -4244,15 +4237,15 @@ dependencies = [ [[package]] name = "zenoh-transport" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "crossbeam-utils", - "flume 0.11.1", + "flume", "futures", "lazy_static", "lz4_flex", - "rand 0.8.5", + "rand 0.8.6", "ringbuffer-spsc", "rsa", "serde", @@ -4278,11 +4271,11 @@ dependencies = [ [[package]] name = "zenoh-util" version = "1.9.0" -source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#12442bb42056afc005e8c3429aa720a1e69e4a45" +source = "git+https://github.com/eclipse-zenoh/zenoh.git?branch=main#aa4767626d5893bb1e931482aa99f7b6307cc9c2" dependencies = [ "async-trait", "const_format", - "flume 0.11.1", + "flume", "home", "humantime", "lazy_static", @@ -4301,24 +4294,6 @@ dependencies = [ "zenoh-result", ] -[[package]] -name = "zenoh_jni" -version = "1.9.0" -dependencies = [ - "android-logd-logger", - "async-std", - "clap", - "flume 0.10.14", - "jni", - "json5", - "rustc_version", - "serde_yaml", - "tracing", - "uhlc", - "zenoh", - "zenoh-ext", -] - [[package]] name = "zerocopy" version = "0.8.48" @@ -4341,9 +4316,9 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" dependencies = [ "zerofrom-derive", ] diff --git a/zenoh-flat-jni/Cargo.toml b/zenoh-flat-jni/Cargo.toml new file mode 100644 index 00000000..60d88a2c --- /dev/null +++ b/zenoh-flat-jni/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "zenoh-flat-jni" +version = "0.1.0" +edition = "2021" + +[features] +default = ["zenoh-ext"] +# Gates the hand-written ZBytes serialization JNI (src/zbytes.rs), which needs +# zenoh-ext's serializer/deserializer. +zenoh-ext = ["dep:zenoh-ext"] + +[dependencies] +# `unstable` must be on to match the `unstable` zenoh features enabled below: +# zenoh-flat's `unstable` feature (= `zenoh/unstable`) gates the QoS surface +# (`Reliability`, `CongestionControl::BlockFirst`, …) in lockstep with the +# zenoh enum variants, so without it the flat↔native conversions go +# non-exhaustive once Cargo unifies `zenoh` with `unstable`. +zenoh-flat = { version = "1.9.0", path = "../../zenoh-flat", features = ["unstable"] } +# Runtime home of the JNI binding helpers and the default `JniBindingError` +# (`::prebindgen::lang::JniBindingError`) that the generated bindings reference. +prebindgen = { path = "../../prebindgen/prebindgen" } +# Direct zenoh/zenoh-ext deps for the self-contained ZBytes serialization JNI. +# Same git rev as zenoh-flat so Cargo unifies the crate instances. +zenoh = { version = "1.9.0", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", features = ["unstable", "internal", "default"], default-features = false } +zenoh-ext = { version = "1.9.0", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", features = ["internal"], default-features = false, optional = true } +jni = "0.21.1" +konst = "0.3.17" +tracing = { version = "0.1", features = ["log"] } + +[lib] +name = "zenoh_flat_jni" +crate-type = ["staticlib", "dylib"] + +[build-dependencies] +# Same feature set as the runtime dep so the captured `FEATURES` / cfg-gated +# `#[prebindgen]` items match what the runtime crate actually compiles. +zenoh-flat = { version = "1.9.0", path = "../../zenoh-flat", features = ["unstable"] } +prebindgen = { path = "../../prebindgen/prebindgen" } +syn = "2" + +# panic = "abort" is required on the JNI boundary — a Rust panic crossing +# into the JVM under unwind is UB. +[profile.release] +debug = false +lto = "fat" +codegen-units = 1 +opt-level = 3 +panic = "abort" \ No newline at end of file diff --git a/zenoh-flat-jni/build.rs b/zenoh-flat-jni/build.rs new file mode 100644 index 00000000..cbdd070c --- /dev/null +++ b/zenoh-flat-jni/build.rs @@ -0,0 +1,353 @@ +use prebindgen::core::{IntoSource, Registry}; +use prebindgen::lang::JniGen; +use syn::parse_quote as pq; + +fn fail(context: &str, err: impl std::fmt::Display) -> ! { + eprintln!("error: prebindgen jnigen {context}: {err}"); + std::process::exit(1); +} + +fn main() { + let jni = JniGen::new() + .handle_locks(true) // Enable handle locks (default, thread-safe) + .source_module(pq!(zenoh_flat)) // how to prefix prebindgen-marked items (functions, types + .package_prefix("io.zenoh.jni") // the package of the generated JNI bindings + .data_class(pq!(Error)) // structured Kotlin data class for Error + .throwable() // …also throwable; JniExt's built-in + // rank-2 Result<_, _> wrapper routes + // Err(Error) through it on the JVM side. + .package("keyexpr") + .ptr_class(pq!(ZKeyExpr)) + .class_object_fun(pq!(z_keyexpr_try_from)) + .class_object_fun(pq!(z_keyexpr_autocanonize)) + .class_fun(pq!(z_keyexpr_intersects)) + .class_fun(pq!(z_keyexpr_includes)) + .class_fun(pq!(z_keyexpr_relation_to)) + .class_fun(pq!(z_keyexpr_join)) + .class_fun(pq!(z_keyexpr_concat)) + .class_fun(pq!(z_keyexpr_clone)) + .class_fun(pq!(z_keyexpr_to_string)) + .enum_class(pq!(SetIntersectionLevel)) + .data_class(pq!(KeyExpr)) + .class_object_fun(pq!(keyexpr_try_from)) + .class_object_fun(pq!(keyexpr_autocanonize)) + .class_object_fun(pq!(keyexpr_intersects)) + .class_object_fun(pq!(keyexpr_includes)) + .class_object_fun(pq!(keyexpr_relation_to)) + .class_object_fun(pq!(keyexpr_join)) + .class_object_fun(pq!(keyexpr_concat)) + // Deterministic single source: the SDK always passes the target's own + // generated `KeyExpr` (data class) at the JNI boundary — String/ZKeyExpr + // conversions happen Kotlin-side — so the twin decodes it directly with + // no runtime find_class/instanceof dispatch. + .into_sources(pq!(KeyExpr), [IntoSource::borrow(pq!(KeyExpr))]) + .package("config") + .ptr_class(pq!(ZConfig)) + .class_object_fun(pq!(z_config_default)) + .class_object_fun(pq!(z_config_from_file)) + .class_object_fun(pq!(z_config_from_json)) + .class_object_fun(pq!(z_config_from_json5)) + .class_object_fun(pq!(z_config_from_yaml)) + .class_fun(pq!(z_config_get_json)) + .class_fun(pq!(z_config_insert_json5)) + .class_fun(pq!(z_config_clone)) + .enum_class(pq!(WhatAmI)) + // ZZenohId is a `Copy` value (zenoh::session::ZenohId, repr(transparent)), + // so it crosses as a raw byte-blob `ByteArray` rather than a closeable + // jlong handle — this also lets `Vec` surface as + // `List` (see z_session_peers_zid/routers_zid below). Its + // accessors become package-level functions (no Kotlin class for a blob). + .value_blob(pq!(ZZenohId)) + .package_fun(pq!(z_zenoh_id_to_bytes)) + .package_fun(pq!(z_zenoh_id_to_string)) + .value_class(pq!(ZenohId)) + .class_object_fun(pq!(zenoh_id_to_string)) + .package("scouting") + .ptr_class(pq!(ZHello)) + .class_fun(pq!(z_hello_whatami)) + .class_fun(pq!(hello_zid)) + // Blob tier kept for full-surface coverage (value_blob demo); the typed + // `hello_zid` above is what real bindings use. + .class_fun(pq!(z_hello_zid)) + .class_fun(pq!(z_hello_locators)) + .data_class(pq!(Hello)) + .ptr_class(pq!(ZScout)) + .package_fun(pq!(z_scout)) + .package_fun(pq!(scout)) + .package("logger") + .package_fun(pq!(init_android_logs)) + .package_fun(pq!(try_init_zenoh_logs_from_env)) + .package_fun(pq!(init_zenoh_logs_from_env_or)) + .package("qos") + .enum_class(pq!(Reliability)) + .enum_class(pq!(Priority)) + .enum_class(pq!(CongestionControl)) + .package("bytes") + .ptr_class(pq!(ZZBytes)) + .class_fun(pq!(z_zbytes_to_bytes)) + .class_fun(pq!(z_zbytes_clone)) + .class_object_fun(pq!(z_zbytes_from_vec)) + // NOTE: `z_zbytes_from_slice(&[u8])` is the C-pointer constructor shape + // (`const uint8_t* + size`); its JNI form is `z_zbytes_from_vec(Vec)` + // above (→ `ByteArray`). The `&[u8]` slice input has no JNI representation, + // so it's intentionally not exported here. + .value_class(pq!(ZBytes)) + .ptr_class(pq!(ZEncoding)) + .class_fun(pq!(z_encoding_id)) + .class_fun(pq!(z_encoding_schema)) + .class_fun(pq!(z_encoding_to_string)) + .class_fun(pq!(z_encoding_clone)) + .class_object_fun(pq!(z_encoding_from_string)) + .class_object_fun(pq!(z_encoding_zenoh_bytes)) + .class_object_fun(pq!(z_encoding_zenoh_string)) + .class_object_fun(pq!(z_encoding_zenoh_serialized)) + .class_object_fun(pq!(z_encoding_application_octet_stream)) + .class_object_fun(pq!(z_encoding_text_plain)) + .class_object_fun(pq!(z_encoding_application_json)) + .class_object_fun(pq!(z_encoding_text_json)) + .class_object_fun(pq!(z_encoding_application_cdr)) + .class_object_fun(pq!(z_encoding_application_cbor)) + .class_object_fun(pq!(z_encoding_application_yaml)) + .class_object_fun(pq!(z_encoding_text_yaml)) + .class_object_fun(pq!(z_encoding_text_json5)) + .class_object_fun(pq!(z_encoding_application_python_serialized_object)) + .class_object_fun(pq!(z_encoding_application_protobuf)) + .class_object_fun(pq!(z_encoding_application_java_serialized_object)) + .class_object_fun(pq!(z_encoding_application_openmetrics_text)) + .class_object_fun(pq!(z_encoding_image_png)) + .class_object_fun(pq!(z_encoding_image_jpeg)) + .class_object_fun(pq!(z_encoding_image_gif)) + .class_object_fun(pq!(z_encoding_image_bmp)) + .class_object_fun(pq!(z_encoding_image_webp)) + .class_object_fun(pq!(z_encoding_application_xml)) + .class_object_fun(pq!(z_encoding_application_x_www_form_urlencoded)) + .class_object_fun(pq!(z_encoding_text_html)) + .class_object_fun(pq!(z_encoding_text_xml)) + .class_object_fun(pq!(z_encoding_text_css)) + .class_object_fun(pq!(z_encoding_text_javascript)) + .class_object_fun(pq!(z_encoding_text_markdown)) + .class_object_fun(pq!(z_encoding_text_csv)) + .class_object_fun(pq!(z_encoding_application_sql)) + .class_object_fun(pq!(z_encoding_application_coap_payload)) + .class_object_fun(pq!(z_encoding_application_json_patch_json)) + .class_object_fun(pq!(z_encoding_application_json_seq)) + .class_object_fun(pq!(z_encoding_application_jsonpath)) + .class_object_fun(pq!(z_encoding_application_jwt)) + .class_object_fun(pq!(z_encoding_application_mp4)) + .class_object_fun(pq!(z_encoding_application_soap_xml)) + .class_object_fun(pq!(z_encoding_application_yang)) + .class_object_fun(pq!(z_encoding_audio_aac)) + .class_object_fun(pq!(z_encoding_audio_flac)) + .class_object_fun(pq!(z_encoding_audio_mp4)) + .class_object_fun(pq!(z_encoding_audio_ogg)) + .class_object_fun(pq!(z_encoding_audio_vorbis)) + .class_object_fun(pq!(z_encoding_video_h261)) + .class_object_fun(pq!(z_encoding_video_h263)) + .class_object_fun(pq!(z_encoding_video_h264)) + .class_object_fun(pq!(z_encoding_video_h265)) + .class_object_fun(pq!(z_encoding_video_h266)) + .class_object_fun(pq!(z_encoding_video_mp4)) + .class_object_fun(pq!(z_encoding_video_ogg)) + .class_object_fun(pq!(z_encoding_video_raw)) + .class_object_fun(pq!(z_encoding_video_vp8)) + .class_object_fun(pq!(z_encoding_video_vp9)) + .data_class(pq!(Encoding)) + .class_fun(pq!(encoding_to_string)) + .class_object_fun(pq!(encoding_from_string)) + .class_object_fun(pq!(encoding_zenoh_bytes)) + .class_object_fun(pq!(encoding_zenoh_string)) + .class_object_fun(pq!(encoding_zenoh_serialized)) + .class_object_fun(pq!(encoding_application_octet_stream)) + .class_object_fun(pq!(encoding_text_plain)) + .class_object_fun(pq!(encoding_application_json)) + .class_object_fun(pq!(encoding_text_json)) + .class_object_fun(pq!(encoding_application_cdr)) + .class_object_fun(pq!(encoding_application_cbor)) + .class_object_fun(pq!(encoding_application_yaml)) + .class_object_fun(pq!(encoding_text_yaml)) + .class_object_fun(pq!(encoding_text_json5)) + .class_object_fun(pq!(encoding_application_python_serialized_object)) + .class_object_fun(pq!(encoding_application_protobuf)) + .class_object_fun(pq!(encoding_application_java_serialized_object)) + .class_object_fun(pq!(encoding_application_openmetrics_text)) + .class_object_fun(pq!(encoding_image_png)) + .class_object_fun(pq!(encoding_image_jpeg)) + .class_object_fun(pq!(encoding_image_gif)) + .class_object_fun(pq!(encoding_image_bmp)) + .class_object_fun(pq!(encoding_image_webp)) + .class_object_fun(pq!(encoding_application_xml)) + .class_object_fun(pq!(encoding_application_x_www_form_urlencoded)) + .class_object_fun(pq!(encoding_text_html)) + .class_object_fun(pq!(encoding_text_xml)) + .class_object_fun(pq!(encoding_text_css)) + .class_object_fun(pq!(encoding_text_javascript)) + .class_object_fun(pq!(encoding_text_markdown)) + .class_object_fun(pq!(encoding_text_csv)) + .class_object_fun(pq!(encoding_application_sql)) + .class_object_fun(pq!(encoding_application_coap_payload)) + .class_object_fun(pq!(encoding_application_json_patch_json)) + .class_object_fun(pq!(encoding_application_json_seq)) + .class_object_fun(pq!(encoding_application_jsonpath)) + .class_object_fun(pq!(encoding_application_jwt)) + .class_object_fun(pq!(encoding_application_mp4)) + .class_object_fun(pq!(encoding_application_soap_xml)) + .class_object_fun(pq!(encoding_application_yang)) + .class_object_fun(pq!(encoding_audio_aac)) + .class_object_fun(pq!(encoding_audio_flac)) + .class_object_fun(pq!(encoding_audio_mp4)) + .class_object_fun(pq!(encoding_audio_ogg)) + .class_object_fun(pq!(encoding_audio_vorbis)) + .class_object_fun(pq!(encoding_video_h261)) + .class_object_fun(pq!(encoding_video_h263)) + .class_object_fun(pq!(encoding_video_h264)) + .class_object_fun(pq!(encoding_video_h265)) + .class_object_fun(pq!(encoding_video_h266)) + .class_object_fun(pq!(encoding_video_mp4)) + .class_object_fun(pq!(encoding_video_ogg)) + .class_object_fun(pq!(encoding_video_raw)) + .class_object_fun(pq!(encoding_video_vp8)) + .class_object_fun(pq!(encoding_video_vp9)) + .package("time") + .ptr_class(pq!(ZTimestamp)) + .class_fun(pq!(z_timestamp_ntp64)) + .class_fun(pq!(z_timestamp_id)) + .class_fun(pq!(z_timestamp_expand)) + .data_class(pq!(Timestamp)) + .package("sample") + .enum_class(pq!(SampleKind)) + .ptr_class(pq!(ZSample)) + .class_fun(pq!(z_sample_key_expr)) + .class_fun(pq!(z_sample_payload)) + .class_fun(pq!(z_sample_encoding)) + .class_fun(pq!(z_sample_kind)) + .class_fun(pq!(z_sample_timestamp)) + .class_fun(pq!(z_sample_express)) + .class_fun(pq!(z_sample_priority)) + .class_fun(pq!(z_sample_congestion_control)) + .class_fun(pq!(z_sample_attachment)) + .class_fun(pq!(z_sample_expand)) + .data_class(pq!(Sample)) + .package("pubsub") + .ptr_class(pq!(ZPublisher)) + .class_fun(pq!(z_publisher_put)) + .class_fun(pq!(z_publisher_delete)) + // Expanded (`impl Into<…>`) ergonomic twins. + .class_fun(pq!(publisher_put)) + .class_fun(pq!(publisher_delete)) + .ptr_class(pq!(ZSubscriber)) + .package("query") + .ptr_class(pq!(ZQueryable)) + .ptr_class(pq!(ZQuerier)) + .class_fun(pq!(z_querier_get)) + .class_fun(pq!(querier_get)) + .enum_class(pq!(ReplyKeyExpr)) + .enum_class(pq!(QueryTarget)) + .enum_class(pq!(ConsolidationMode)) + .ptr_class(pq!(ZQuery)) + .class_fun(pq!(z_query_reply_success)) + .class_fun(pq!(z_query_reply_error)) + .class_fun(pq!(z_query_reply_delete)) + .class_fun(pq!(z_query_keyexpr)) + .class_fun(pq!(z_query_parameters)) + .class_fun(pq!(z_query_payload)) + .class_fun(pq!(z_query_encoding)) + .class_fun(pq!(z_query_expand)) + // Expanded (`impl Into<…>`) ergonomic reply twins. + .class_fun(pq!(query_reply_success)) + .class_fun(pq!(query_reply_error)) + .class_fun(pq!(query_reply_delete)) + .data_class(pq!(Query)) + .ptr_class(pq!(ZReply)) + .class_fun(pq!(reply_replier_zid)) + // Blob tier kept for full-surface coverage (value_blob demo); the typed + // `reply_replier_zid` above is what real bindings use. + .class_fun(pq!(z_reply_replier_zid)) + .class_fun(pq!(z_reply_replier_eid)) + .class_fun(pq!(z_reply_is_ok)) + .class_fun(pq!(z_reply_sample)) + .class_fun(pq!(z_reply_error_payload)) + .class_fun(pq!(z_reply_error_encoding)) + .class_fun(pq!(z_reply_expand)) + .data_class(pq!(Reply)) + .package("liveliness") + .ptr_class(pq!(ZLivelinessToken)) + .package("session") + .ptr_class(pq!(ZSession)) + .class_object_fun(pq!(z_open)) + .class_fun(pq!(z_session_declare_publisher)) + .class_fun(pq!(z_session_put)) + .class_fun(pq!(z_session_delete)) + .class_fun(pq!(z_session_declare_subscriber)) + .class_fun(pq!(session_declare_subscriber)) + .class_fun(pq!(z_session_declare_querier)) + .class_fun(pq!(z_session_declare_queryable)) + .class_fun(pq!(session_declare_queryable)) + .class_fun(pq!(z_session_declare_keyexpr)) + .class_fun(pq!(z_session_undeclare_keyexpr)) + .class_fun(pq!(z_session_get)) + .class_fun(pq!(session_get)) + // Expanded (`impl Into<…>`) ergonomic twins of the declare/put/delete API. + .class_fun(pq!(session_declare_publisher)) + .class_fun(pq!(session_declare_querier)) + .class_fun(pq!(session_put)) + .class_fun(pq!(session_delete)) + // Real, natively-representable zid API: `ZenohId` value-class twins + // (`sessionZid(): ZenohId`, `sessionPeersZid(): List`). This is + // what downstream zenoh-java uses. + .class_fun(pq!(session_zid)) + .class_fun(pq!(session_peers_zid)) + .class_fun(pq!(session_routers_zid)) + // value_blob demonstration: the same zid surfaced as the opaque-handle + // tier's `ZZenohId` — a `Copy` type carried as a `ByteArray` value + // (no rust-side close/lock), in both the Direct (`zSessionZid`) and + // `Vec` (`zSessionPeersZid`/`zSessionRoutersZid` → `List`) + // shapes value_blob was built for. Not used by the real zenoh-java API. + .class_fun(pq!(z_session_zid)) + .class_fun(pq!(z_session_peers_zid)) + .class_fun(pq!(z_session_routers_zid)) + .class_fun(pq!(z_liveliness_declare_token)) + .class_fun(pq!(liveliness_declare_token)) + .class_fun(pq!(z_liveliness_get)) + .class_fun(pq!(liveliness_get)) + .class_fun(pq!(z_liveliness_declare_subscriber)) + .class_fun(pq!(liveliness_declare_subscriber)) + // Deterministic single source (see KeyExpr note above): the SDK passes + // the value-class `ZBytes` (payload.into().inner) and the data-class + // `Encoding` (encoding.toFlat()) directly — no runtime dispatch. + .into_sources(pq!(ZBytes), [IntoSource::borrow(pq!(ZBytes))]) + .into_sources(pq!(Encoding), [IntoSource::borrow(pq!(Encoding))]) + ; + + let source = prebindgen::Source::new(zenoh_flat::PREBINDGEN_OUT_DIR); + let mut registry = match Registry::from_items(source.items_all()) { + Ok(registry) => registry, + Err(err) => fail("scan failed", err), + }; + let rust_path = match registry.write_rust(&jni, "zenoh_flat_jni.rs") { + Ok(path) => path, + Err(err) => fail("write_rust failed", err), + }; + println!( + "cargo:warning=Generated bindings at: {}", + rust_path.display() + ); + + // ── Write Kotlin output ─────────────────────────────────────────── + // All generated Kotlin lives under `generated-kotlin/`; the runtime + // module's Gradle source set picks it up via + // `kotlin.srcDir("$rootDir/zenoh-flat-jni/generated-kotlin")`. + let kotlin_root = std::path::Path::new("generated-kotlin"); + // Remove stale generated files so package moves don't leave old classes + // behind (e.g. io/zenoh/jni/* and io/zenoh/jni//* side-by-side). + if let Err(err) = std::fs::remove_dir_all(kotlin_root) { + if err.kind() != std::io::ErrorKind::NotFound { + fail("cleanup generated-kotlin failed", err); + } + } + for path in match jni.write_kotlin(®istry, kotlin_root) { + Ok(paths) => paths, + Err(err) => fail("write_kotlin failed", err), + } { + println!("cargo:warning=Wrote {}", path.display()); + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/Error.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/Error.kt new file mode 100644 index 00000000..51891e8b --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/Error.kt @@ -0,0 +1,14 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni + +public data class Error( + override val message: String, +) : Exception(message) { + public companion object { + @JvmStatic + public fun fromParts( + message: String + ): Error = + Error(message) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/JNINative.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/JNINative.kt new file mode 100644 index 00000000..c43daf4c --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/JNINative.kt @@ -0,0 +1,260 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni + +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZEncoding +import io.zenoh.jni.bytes.ZZBytes +import io.zenoh.jni.callbacks.Callback +import io.zenoh.jni.callbacks.HelloCallback +import io.zenoh.jni.callbacks.QueryCallback +import io.zenoh.jni.callbacks.ReplyCallback +import io.zenoh.jni.callbacks.SampleCallback +import io.zenoh.jni.callbacks.ZHelloCallback +import io.zenoh.jni.callbacks.ZQueryCallback +import io.zenoh.jni.callbacks.ZReplyCallback +import io.zenoh.jni.callbacks.ZSampleCallback +import io.zenoh.jni.config.WhatAmI +import io.zenoh.jni.config.ZConfig +import io.zenoh.jni.config.ZZenohId +import io.zenoh.jni.config.ZenohId +import io.zenoh.jni.keyexpr.KeyExpr +import io.zenoh.jni.keyexpr.SetIntersectionLevel +import io.zenoh.jni.keyexpr.ZKeyExpr +import io.zenoh.jni.liveliness.ZLivelinessToken +import io.zenoh.jni.pubsub.ZPublisher +import io.zenoh.jni.pubsub.ZSubscriber +import io.zenoh.jni.qos.CongestionControl +import io.zenoh.jni.qos.Priority +import io.zenoh.jni.query.Query +import io.zenoh.jni.query.Reply +import io.zenoh.jni.query.ZQuerier +import io.zenoh.jni.query.ZQueryable +import io.zenoh.jni.sample.Sample +import io.zenoh.jni.sample.SampleKind +import io.zenoh.jni.sample.ZSample +import io.zenoh.jni.scouting.ZScout +import io.zenoh.jni.session.ZSession +import io.zenoh.jni.time.Timestamp +import io.zenoh.jni.time.ZTimestamp + +internal object JNINative { + external fun encodingApplicationCbor(): Encoding + external fun encodingApplicationCdr(): Encoding + external fun encodingApplicationCoapPayload(): Encoding + external fun encodingApplicationJavaSerializedObject(): Encoding + external fun encodingApplicationJson(): Encoding + external fun encodingApplicationJsonPatchJson(): Encoding + external fun encodingApplicationJsonSeq(): Encoding + external fun encodingApplicationJsonpath(): Encoding + external fun encodingApplicationJwt(): Encoding + external fun encodingApplicationMp4(): Encoding + external fun encodingApplicationOctetStream(): Encoding + external fun encodingApplicationOpenmetricsText(): Encoding + external fun encodingApplicationProtobuf(): Encoding + external fun encodingApplicationPythonSerializedObject(): Encoding + external fun encodingApplicationSoapXml(): Encoding + external fun encodingApplicationSql(): Encoding + external fun encodingApplicationXWwwFormUrlencoded(): Encoding + external fun encodingApplicationXml(): Encoding + external fun encodingApplicationYaml(): Encoding + external fun encodingApplicationYang(): Encoding + external fun encodingAudioAac(): Encoding + external fun encodingAudioFlac(): Encoding + external fun encodingAudioMp4(): Encoding + external fun encodingAudioOgg(): Encoding + external fun encodingAudioVorbis(): Encoding + external fun encodingFromString(s: String): Encoding + external fun encodingImageBmp(): Encoding + external fun encodingImageGif(): Encoding + external fun encodingImageJpeg(): Encoding + external fun encodingImagePng(): Encoding + external fun encodingImageWebp(): Encoding + external fun encodingTextCss(): Encoding + external fun encodingTextCsv(): Encoding + external fun encodingTextHtml(): Encoding + external fun encodingTextJavascript(): Encoding + external fun encodingTextJson(): Encoding + external fun encodingTextJson5(): Encoding + external fun encodingTextMarkdown(): Encoding + external fun encodingTextPlain(): Encoding + external fun encodingTextXml(): Encoding + external fun encodingTextYaml(): Encoding + external fun encodingToString(eId: Int, eSchema: String?): String + external fun encodingVideoH261(): Encoding + external fun encodingVideoH263(): Encoding + external fun encodingVideoH264(): Encoding + external fun encodingVideoH265(): Encoding + external fun encodingVideoH266(): Encoding + external fun encodingVideoMp4(): Encoding + external fun encodingVideoOgg(): Encoding + external fun encodingVideoRaw(): Encoding + external fun encodingVideoVp8(): Encoding + external fun encodingVideoVp9(): Encoding + external fun encodingZenohBytes(): Encoding + external fun encodingZenohSerialized(): Encoding + external fun encodingZenohString(): Encoding + external fun helloZid(h: Long): ByteArray + external fun initAndroidLogs(filter: String) + external fun initZenohLogsFromEnvOr(fallbackFilter: String) + external fun keyexprAutocanonize(s: String): KeyExpr + external fun keyexprConcat(a: KeyExpr, b: String): KeyExpr + external fun keyexprIncludes(a: KeyExpr, b: KeyExpr): Boolean + external fun keyexprIntersects(a: KeyExpr, b: KeyExpr): Boolean + external fun keyexprJoin(a: KeyExpr, b: String): KeyExpr + external fun keyexprRelationTo(a: KeyExpr, b: KeyExpr): Int + external fun keyexprTryFrom(s: String): KeyExpr + external fun livelinessDeclareSubscriber(session: Long, keyExpr: KeyExpr, history: Boolean, callback: SampleCallback, onClose: Callback): Long + external fun livelinessDeclareToken(session: Long, keyExpr: KeyExpr): Long + external fun livelinessGet(session: Long, keyExpr: KeyExpr, timeoutMs: Long, callback: ReplyCallback, onClose: Callback) + external fun publisherDelete(publisher: Long, attachment: ByteArray?) + external fun publisherPut(publisher: Long, payload: ByteArray, encodingPresent: Boolean, encodingId: Int, encodingSchema: String?, attachment: ByteArray?) + external fun querierGet(querier: Long, parameters: String?, payload: ByteArray?, encodingPresent: Boolean, encodingId: Int, encodingSchema: String?, attachment: ByteArray?, callback: ReplyCallback, onClose: Callback) + external fun queryReplyDelete(query: Long, keyExpr: KeyExpr, timestampNtp64: Long?, attachment: ByteArray?, express: Boolean?) + external fun queryReplyError(query: Long, payload: ByteArray, encodingPresent: Boolean, encodingId: Int, encodingSchema: String?) + external fun queryReplySuccess(query: Long, keyExpr: KeyExpr, payload: ByteArray, encodingPresent: Boolean, encodingId: Int, encodingSchema: String?, timestampNtp64: Long?, attachment: ByteArray?, express: Boolean?) + external fun replyReplierZid(r: Long): ByteArray? + external fun scout(whatami: Int, config: Long, callback: HelloCallback, onClose: Callback): Long + external fun sessionDeclarePublisher(session: Long, keyExpr: KeyExpr, congestionControl: Int?, priority: Int?, express: Boolean?, reliability: Int?): Long + external fun sessionDeclareQuerier(session: Long, keyExpr: KeyExpr, target: Int?, consolidation: Int?, congestionControl: Int?, priority: Int?, express: Boolean?, timeoutMs: Long?, acceptReplies: Int?): Long + external fun sessionDeclareQueryable(session: Long, keyExpr: KeyExpr, complete: Boolean?, callback: QueryCallback, onClose: Callback): Long + external fun sessionDeclareSubscriber(session: Long, keyExpr: KeyExpr, callback: SampleCallback, onClose: Callback): Long + external fun sessionDelete(session: Long, keyExpr: KeyExpr, congestionControl: Int?, priority: Int?, express: Boolean?, attachment: ByteArray?, reliability: Int?) + external fun sessionGet(session: Long, keyExpr: KeyExpr, parameters: String?, timeoutMs: Long?, target: Int?, consolidation: Int?, acceptReplies: Int?, congestionControl: Int?, priority: Int?, express: Boolean?, payload: ByteArray?, encodingPresent: Boolean, encodingId: Int, encodingSchema: String?, attachment: ByteArray?, callback: ReplyCallback, onClose: Callback) + external fun sessionPeersZid(session: Long): List + external fun sessionPut(session: Long, keyExpr: KeyExpr, payload: ByteArray, encodingPresent: Boolean, encodingId: Int, encodingSchema: String?, congestionControl: Int?, priority: Int?, express: Boolean?, attachment: ByteArray?, reliability: Int?) + external fun sessionRoutersZid(session: Long): List + external fun sessionZid(session: Long): ByteArray + external fun tryInitZenohLogsFromEnv() + external fun zConfigClone(c: Long): Long + external fun zConfigDefault(): Long + external fun zConfigFromFile(path: String): Long + external fun zConfigFromJson(s: String): Long + external fun zConfigFromJson5(s: String): Long + external fun zConfigFromYaml(s: String): Long + external fun zConfigGetJson(c: Long, key: String): String + external fun zConfigInsertJson5(c: Long, key: String, value: String) + external fun zEncodingApplicationCbor(): Long + external fun zEncodingApplicationCdr(): Long + external fun zEncodingApplicationCoapPayload(): Long + external fun zEncodingApplicationJavaSerializedObject(): Long + external fun zEncodingApplicationJson(): Long + external fun zEncodingApplicationJsonPatchJson(): Long + external fun zEncodingApplicationJsonSeq(): Long + external fun zEncodingApplicationJsonpath(): Long + external fun zEncodingApplicationJwt(): Long + external fun zEncodingApplicationMp4(): Long + external fun zEncodingApplicationOctetStream(): Long + external fun zEncodingApplicationOpenmetricsText(): Long + external fun zEncodingApplicationProtobuf(): Long + external fun zEncodingApplicationPythonSerializedObject(): Long + external fun zEncodingApplicationSoapXml(): Long + external fun zEncodingApplicationSql(): Long + external fun zEncodingApplicationXWwwFormUrlencoded(): Long + external fun zEncodingApplicationXml(): Long + external fun zEncodingApplicationYaml(): Long + external fun zEncodingApplicationYang(): Long + external fun zEncodingAudioAac(): Long + external fun zEncodingAudioFlac(): Long + external fun zEncodingAudioMp4(): Long + external fun zEncodingAudioOgg(): Long + external fun zEncodingAudioVorbis(): Long + external fun zEncodingClone(e: Long): Long + external fun zEncodingFromString(s: String): Long + external fun zEncodingId(e: Long): Int + external fun zEncodingImageBmp(): Long + external fun zEncodingImageGif(): Long + external fun zEncodingImageJpeg(): Long + external fun zEncodingImagePng(): Long + external fun zEncodingImageWebp(): Long + external fun zEncodingSchema(e: Long): String + external fun zEncodingTextCss(): Long + external fun zEncodingTextCsv(): Long + external fun zEncodingTextHtml(): Long + external fun zEncodingTextJavascript(): Long + external fun zEncodingTextJson(): Long + external fun zEncodingTextJson5(): Long + external fun zEncodingTextMarkdown(): Long + external fun zEncodingTextPlain(): Long + external fun zEncodingTextXml(): Long + external fun zEncodingTextYaml(): Long + external fun zEncodingToString(e: Long): String + external fun zEncodingVideoH261(): Long + external fun zEncodingVideoH263(): Long + external fun zEncodingVideoH264(): Long + external fun zEncodingVideoH265(): Long + external fun zEncodingVideoH266(): Long + external fun zEncodingVideoMp4(): Long + external fun zEncodingVideoOgg(): Long + external fun zEncodingVideoRaw(): Long + external fun zEncodingVideoVp8(): Long + external fun zEncodingVideoVp9(): Long + external fun zEncodingZenohBytes(): Long + external fun zEncodingZenohSerialized(): Long + external fun zEncodingZenohString(): Long + external fun zHelloLocators(h: Long): List + external fun zHelloWhatami(h: Long): Int + external fun zHelloZid(h: Long): ByteArray + external fun zKeyexprAutocanonize(s: String): Long + external fun zKeyexprClone(ke: Long): Long + external fun zKeyexprConcat(a: Long, b: String): Long + external fun zKeyexprIncludes(a: Long, b: Long): Boolean + external fun zKeyexprIntersects(a: Long, b: Long): Boolean + external fun zKeyexprJoin(a: Long, b: String): Long + external fun zKeyexprRelationTo(a: Long, b: Long): Int + external fun zKeyexprToString(ke: Long): String + external fun zKeyexprTryFrom(s: String): Long + external fun zLivelinessDeclareSubscriber(session: Long, keyExpr: Long, history: Boolean, callback: ZSampleCallback, onClose: Callback): Long + external fun zLivelinessDeclareToken(session: Long, keyExpr: Long): Long + external fun zLivelinessGet(session: Long, keyExpr: Long, timeoutMs: Long, callback: ZReplyCallback, onClose: Callback) + external fun zOpen(config: Long): Long + external fun zPublisherDelete(publisher: Long, attachment: Long?) + external fun zPublisherPut(publisher: Long, payload: Long, encoding: Long, attachment: Long?) + external fun zQuerierGet(querier: Long, parameters: String?, payload: Long?, encoding: Long, attachment: Long?, callback: ZReplyCallback, onClose: Callback) + external fun zQueryEncoding(q: Long): Long + external fun zQueryExpand(query: Long): Query + external fun zQueryKeyexpr(q: Long): Long + external fun zQueryParameters(q: Long): String + external fun zQueryPayload(q: Long): Long + external fun zQueryReplyDelete(query: Long, keyExpr: Long, timestampNtp64: Long?, attachment: Long?, express: Boolean?) + external fun zQueryReplyError(query: Long, payload: Long, encoding: Long) + external fun zQueryReplySuccess(query: Long, keyExpr: Long, payload: Long, encoding: Long, timestampNtp64: Long?, attachment: Long?, express: Boolean?) + external fun zReplyErrorEncoding(r: Long): Long + external fun zReplyErrorPayload(r: Long): Long + external fun zReplyExpand(r: Long): Reply + external fun zReplyIsOk(r: Long): Boolean + external fun zReplyReplierEid(r: Long): Int + external fun zReplyReplierZid(r: Long): ByteArray? + external fun zReplySample(r: Long): Long + external fun zSampleAttachment(s: Long): Long + external fun zSampleCongestionControl(s: Long): Int + external fun zSampleEncoding(s: Long): Long + external fun zSampleExpand(s: Long): Sample + external fun zSampleExpress(s: Long): Boolean + external fun zSampleKeyExpr(s: Long): Long + external fun zSampleKind(s: Long): Int + external fun zSamplePayload(s: Long): Long + external fun zSamplePriority(s: Long): Int + external fun zSampleTimestamp(s: Long): Long + external fun zScout(whatami: Int, config: Long, callback: ZHelloCallback, onClose: Callback): Long + external fun zSessionDeclareKeyexpr(session: Long, keyExpr: String): Long + external fun zSessionDeclarePublisher(session: Long, keyExpr: Long, congestionControl: Int?, priority: Int?, express: Boolean?, reliability: Int?): Long + external fun zSessionDeclareQuerier(session: Long, keyExpr: Long, target: Int?, consolidation: Int?, congestionControl: Int?, priority: Int?, express: Boolean?, timeoutMs: Long?, acceptReplies: Int?): Long + external fun zSessionDeclareQueryable(session: Long, keyExpr: Long, complete: Boolean?, callback: ZQueryCallback, onClose: Callback): Long + external fun zSessionDeclareSubscriber(session: Long, keyExpr: Long, callback: ZSampleCallback, onClose: Callback): Long + external fun zSessionDelete(session: Long, keyExpr: Long, congestionControl: Int?, priority: Int?, express: Boolean?, attachment: Long?, reliability: Int?) + external fun zSessionGet(session: Long, keyExpr: Long, parameters: String?, timeoutMs: Long?, target: Int?, consolidation: Int?, acceptReplies: Int?, congestionControl: Int?, priority: Int?, express: Boolean?, payload: Long?, encoding: Long, attachment: Long?, callback: ZReplyCallback, onClose: Callback) + external fun zSessionPeersZid(session: Long): List + external fun zSessionPut(session: Long, keyExpr: Long, payload: Long, encoding: Long, congestionControl: Int?, priority: Int?, express: Boolean?, attachment: Long?, reliability: Int?) + external fun zSessionRoutersZid(session: Long): List + external fun zSessionUndeclareKeyexpr(session: Long, keyExpr: Long) + external fun zSessionZid(session: Long): ByteArray + external fun zTimestampExpand(t: Long): Timestamp + external fun zTimestampId(t: Long): ByteArray + external fun zTimestampNtp64(t: Long): Long + external fun zZbytesClone(z: Long): Long + external fun zZbytesFromVec(bytes: ByteArray): Long + external fun zZbytesToBytes(z: Long): ByteArray + external fun zZenohIdToBytes(z: ByteArray): ByteArray + external fun zZenohIdToString(z: ByteArray): String + external fun zenohIdToString(bytes: ByteArray): String +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/JniBindingError.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/JniBindingError.kt new file mode 100644 index 00000000..6b63eec6 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/JniBindingError.kt @@ -0,0 +1,5 @@ +// Auto-generated by JniGen - do not edit by hand. +package io.zenoh.jni + +/** JVM-side surface for the native Rust `JniBindingError` error. */ +public class JniBindingError(override val message: String? = null) : Exception() diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/NativeHandle.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/NativeHandle.kt new file mode 100644 index 00000000..836674b3 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/NativeHandle.kt @@ -0,0 +1,50 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni + +/** Base class for every typed native handle: owns the raw `Box` pointer + * slot and its monitor. Subclasses add their type-specific `close()` / + * `take()` / `freePtr`. */ +public abstract class NativeHandle(initialPtr: Long) : AutoCloseable { + @Volatile internal var ptr: Long = initialPtr + public fun peek(): Long = ptr + public fun isClosed(): Boolean = ptr == 0L +} + +/** Acquire every handle's monitor in one global order (sorted by raw + * pointer) so concurrent calls touching the same handles can't deadlock, + * then run [body]. Closed handles (`ptr == 0`) are still locked; callers + * re-read and null-check each pointer inside [body]. Scales to any arity. */ +internal fun withSortedHandleLocks(handles: List, body: () -> R): R { + val sorted = handles.sortedBy { it.ptr } + fun rec(i: Int): R = if (i == sorted.size) body() else synchronized(sorted[i]) { rec(i + 1) } + return rec(0) +} +/** Allocation-free single-handle lock (one monitor, nothing to order). */ +internal inline fun withSortedHandleLocks(a: NativeHandle, body: () -> R): R = + synchronized(a) { body() } +/** Allocation-free two-handle lock: order by `ptr` then nest monitors. */ +internal inline fun withSortedHandleLocks( + a: NativeHandle, + b: NativeHandle, + body: () -> R, +): R { + val first: NativeHandle + val second: NativeHandle + if (a.ptr <= b.ptr) { first = a; second = b } else { first = b; second = a } + return synchronized(first) { synchronized(second) { body() } } +} +/** Allocation-free three-handle lock: 3-compare sorting network, then nest. */ +internal inline fun withSortedHandleLocks( + a: NativeHandle, + b: NativeHandle, + c: NativeHandle, + body: () -> R, +): R { + var x = a + var y = b + var z = c + if (x.ptr > y.ptr) { val t = x; x = y; y = t } + if (y.ptr > z.ptr) { val t = y; y = z; z = t } + if (x.ptr > y.ptr) { val t = x; x = y; y = t } + return synchronized(x) { synchronized(y) { synchronized(z) { body() } } } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/Encoding.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/Encoding.kt new file mode 100644 index 00000000..402d0414 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/Encoding.kt @@ -0,0 +1,293 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.bytes + +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError + +public data class Encoding( + val id: Int, + val schema: String?, +) { + @Throws(JniBindingError::class) + public fun encodingToString(): String = + JNINative.encodingToString(this.id, this.schema) + + + public companion object { + @JvmStatic + public fun fromParts( + id: Int, + schema: String? + ): Encoding = + Encoding(id, schema) + @Throws(JniBindingError::class) + public fun encodingFromString(s: String): Encoding = + JNINative.encodingFromString(s) + + + @Throws(JniBindingError::class) + public fun encodingZenohBytes(): Encoding = + JNINative.encodingZenohBytes() + + + @Throws(JniBindingError::class) + public fun encodingZenohString(): Encoding = + JNINative.encodingZenohString() + + + @Throws(JniBindingError::class) + public fun encodingZenohSerialized(): Encoding = + JNINative.encodingZenohSerialized() + + + @Throws(JniBindingError::class) + public fun encodingApplicationOctetStream(): Encoding = + JNINative.encodingApplicationOctetStream() + + + @Throws(JniBindingError::class) + public fun encodingTextPlain(): Encoding = + JNINative.encodingTextPlain() + + + @Throws(JniBindingError::class) + public fun encodingApplicationJson(): Encoding = + JNINative.encodingApplicationJson() + + + @Throws(JniBindingError::class) + public fun encodingTextJson(): Encoding = + JNINative.encodingTextJson() + + + @Throws(JniBindingError::class) + public fun encodingApplicationCdr(): Encoding = + JNINative.encodingApplicationCdr() + + + @Throws(JniBindingError::class) + public fun encodingApplicationCbor(): Encoding = + JNINative.encodingApplicationCbor() + + + @Throws(JniBindingError::class) + public fun encodingApplicationYaml(): Encoding = + JNINative.encodingApplicationYaml() + + + @Throws(JniBindingError::class) + public fun encodingTextYaml(): Encoding = + JNINative.encodingTextYaml() + + + @Throws(JniBindingError::class) + public fun encodingTextJson5(): Encoding = + JNINative.encodingTextJson5() + + + @Throws(JniBindingError::class) + public fun encodingApplicationPythonSerializedObject(): Encoding = + JNINative.encodingApplicationPythonSerializedObject() + + + @Throws(JniBindingError::class) + public fun encodingApplicationProtobuf(): Encoding = + JNINative.encodingApplicationProtobuf() + + + @Throws(JniBindingError::class) + public fun encodingApplicationJavaSerializedObject(): Encoding = + JNINative.encodingApplicationJavaSerializedObject() + + + @Throws(JniBindingError::class) + public fun encodingApplicationOpenmetricsText(): Encoding = + JNINative.encodingApplicationOpenmetricsText() + + + @Throws(JniBindingError::class) + public fun encodingImagePng(): Encoding = + JNINative.encodingImagePng() + + + @Throws(JniBindingError::class) + public fun encodingImageJpeg(): Encoding = + JNINative.encodingImageJpeg() + + + @Throws(JniBindingError::class) + public fun encodingImageGif(): Encoding = + JNINative.encodingImageGif() + + + @Throws(JniBindingError::class) + public fun encodingImageBmp(): Encoding = + JNINative.encodingImageBmp() + + + @Throws(JniBindingError::class) + public fun encodingImageWebp(): Encoding = + JNINative.encodingImageWebp() + + + @Throws(JniBindingError::class) + public fun encodingApplicationXml(): Encoding = + JNINative.encodingApplicationXml() + + + @Throws(JniBindingError::class) + public fun encodingApplicationXWwwFormUrlencoded(): Encoding = + JNINative.encodingApplicationXWwwFormUrlencoded() + + + @Throws(JniBindingError::class) + public fun encodingTextHtml(): Encoding = + JNINative.encodingTextHtml() + + + @Throws(JniBindingError::class) + public fun encodingTextXml(): Encoding = + JNINative.encodingTextXml() + + + @Throws(JniBindingError::class) + public fun encodingTextCss(): Encoding = + JNINative.encodingTextCss() + + + @Throws(JniBindingError::class) + public fun encodingTextJavascript(): Encoding = + JNINative.encodingTextJavascript() + + + @Throws(JniBindingError::class) + public fun encodingTextMarkdown(): Encoding = + JNINative.encodingTextMarkdown() + + + @Throws(JniBindingError::class) + public fun encodingTextCsv(): Encoding = + JNINative.encodingTextCsv() + + + @Throws(JniBindingError::class) + public fun encodingApplicationSql(): Encoding = + JNINative.encodingApplicationSql() + + + @Throws(JniBindingError::class) + public fun encodingApplicationCoapPayload(): Encoding = + JNINative.encodingApplicationCoapPayload() + + + @Throws(JniBindingError::class) + public fun encodingApplicationJsonPatchJson(): Encoding = + JNINative.encodingApplicationJsonPatchJson() + + + @Throws(JniBindingError::class) + public fun encodingApplicationJsonSeq(): Encoding = + JNINative.encodingApplicationJsonSeq() + + + @Throws(JniBindingError::class) + public fun encodingApplicationJsonpath(): Encoding = + JNINative.encodingApplicationJsonpath() + + + @Throws(JniBindingError::class) + public fun encodingApplicationJwt(): Encoding = + JNINative.encodingApplicationJwt() + + + @Throws(JniBindingError::class) + public fun encodingApplicationMp4(): Encoding = + JNINative.encodingApplicationMp4() + + + @Throws(JniBindingError::class) + public fun encodingApplicationSoapXml(): Encoding = + JNINative.encodingApplicationSoapXml() + + + @Throws(JniBindingError::class) + public fun encodingApplicationYang(): Encoding = + JNINative.encodingApplicationYang() + + + @Throws(JniBindingError::class) + public fun encodingAudioAac(): Encoding = + JNINative.encodingAudioAac() + + + @Throws(JniBindingError::class) + public fun encodingAudioFlac(): Encoding = + JNINative.encodingAudioFlac() + + + @Throws(JniBindingError::class) + public fun encodingAudioMp4(): Encoding = + JNINative.encodingAudioMp4() + + + @Throws(JniBindingError::class) + public fun encodingAudioOgg(): Encoding = + JNINative.encodingAudioOgg() + + + @Throws(JniBindingError::class) + public fun encodingAudioVorbis(): Encoding = + JNINative.encodingAudioVorbis() + + + @Throws(JniBindingError::class) + public fun encodingVideoH261(): Encoding = + JNINative.encodingVideoH261() + + + @Throws(JniBindingError::class) + public fun encodingVideoH263(): Encoding = + JNINative.encodingVideoH263() + + + @Throws(JniBindingError::class) + public fun encodingVideoH264(): Encoding = + JNINative.encodingVideoH264() + + + @Throws(JniBindingError::class) + public fun encodingVideoH265(): Encoding = + JNINative.encodingVideoH265() + + + @Throws(JniBindingError::class) + public fun encodingVideoH266(): Encoding = + JNINative.encodingVideoH266() + + + @Throws(JniBindingError::class) + public fun encodingVideoMp4(): Encoding = + JNINative.encodingVideoMp4() + + + @Throws(JniBindingError::class) + public fun encodingVideoOgg(): Encoding = + JNINative.encodingVideoOgg() + + + @Throws(JniBindingError::class) + public fun encodingVideoRaw(): Encoding = + JNINative.encodingVideoRaw() + + + @Throws(JniBindingError::class) + public fun encodingVideoVp8(): Encoding = + JNINative.encodingVideoVp8() + + + @Throws(JniBindingError::class) + public fun encodingVideoVp9(): Encoding = + JNINative.encodingVideoVp9() + + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/ZBytes.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/ZBytes.kt new file mode 100644 index 00000000..d830b442 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/ZBytes.kt @@ -0,0 +1,5 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.bytes + +@JvmInline +public value class ZBytes(val bytes: ByteArray) diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/ZEncoding.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/ZEncoding.kt new file mode 100644 index 00000000..864c7318 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/ZEncoding.kt @@ -0,0 +1,283 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.bytes + +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZEncoding`. */ +public class ZEncoding(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZEncoding { + val p = ptr + ptr = 0L + return ZEncoding(p) + } + + @Throws(JniBindingError::class) + public fun zEncodingId(): Int { + return withSortedHandleLocks(this) { + val e_ptr = this.ptr + if (e_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zEncodingId(e_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zEncodingSchema(): String { + return withSortedHandleLocks(this) { + val e_ptr = this.ptr + if (e_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zEncodingSchema(e_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zEncodingToString(): String { + return withSortedHandleLocks(this) { + val e_ptr = this.ptr + if (e_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zEncodingToString(e_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zEncodingClone(): ZEncoding { + return withSortedHandleLocks(this) { + val e_ptr = this.ptr + if (e_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZEncoding(JNINative.zEncodingClone(e_ptr)) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + + @Throws(JniBindingError::class) + public fun zEncodingFromString(s: String): ZEncoding = + ZEncoding(JNINative.zEncodingFromString(s)) + + @Throws(JniBindingError::class) + public fun zEncodingZenohBytes(): ZEncoding = + ZEncoding(JNINative.zEncodingZenohBytes()) + + @Throws(JniBindingError::class) + public fun zEncodingZenohString(): ZEncoding = + ZEncoding(JNINative.zEncodingZenohString()) + + @Throws(JniBindingError::class) + public fun zEncodingZenohSerialized(): ZEncoding = + ZEncoding(JNINative.zEncodingZenohSerialized()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationOctetStream(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationOctetStream()) + + @Throws(JniBindingError::class) + public fun zEncodingTextPlain(): ZEncoding = + ZEncoding(JNINative.zEncodingTextPlain()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationJson(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationJson()) + + @Throws(JniBindingError::class) + public fun zEncodingTextJson(): ZEncoding = + ZEncoding(JNINative.zEncodingTextJson()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationCdr(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationCdr()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationCbor(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationCbor()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationYaml(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationYaml()) + + @Throws(JniBindingError::class) + public fun zEncodingTextYaml(): ZEncoding = + ZEncoding(JNINative.zEncodingTextYaml()) + + @Throws(JniBindingError::class) + public fun zEncodingTextJson5(): ZEncoding = + ZEncoding(JNINative.zEncodingTextJson5()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationPythonSerializedObject(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationPythonSerializedObject()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationProtobuf(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationProtobuf()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationJavaSerializedObject(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationJavaSerializedObject()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationOpenmetricsText(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationOpenmetricsText()) + + @Throws(JniBindingError::class) + public fun zEncodingImagePng(): ZEncoding = + ZEncoding(JNINative.zEncodingImagePng()) + + @Throws(JniBindingError::class) + public fun zEncodingImageJpeg(): ZEncoding = + ZEncoding(JNINative.zEncodingImageJpeg()) + + @Throws(JniBindingError::class) + public fun zEncodingImageGif(): ZEncoding = + ZEncoding(JNINative.zEncodingImageGif()) + + @Throws(JniBindingError::class) + public fun zEncodingImageBmp(): ZEncoding = + ZEncoding(JNINative.zEncodingImageBmp()) + + @Throws(JniBindingError::class) + public fun zEncodingImageWebp(): ZEncoding = + ZEncoding(JNINative.zEncodingImageWebp()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationXml(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationXml()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationXWwwFormUrlencoded(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationXWwwFormUrlencoded()) + + @Throws(JniBindingError::class) + public fun zEncodingTextHtml(): ZEncoding = + ZEncoding(JNINative.zEncodingTextHtml()) + + @Throws(JniBindingError::class) + public fun zEncodingTextXml(): ZEncoding = + ZEncoding(JNINative.zEncodingTextXml()) + + @Throws(JniBindingError::class) + public fun zEncodingTextCss(): ZEncoding = + ZEncoding(JNINative.zEncodingTextCss()) + + @Throws(JniBindingError::class) + public fun zEncodingTextJavascript(): ZEncoding = + ZEncoding(JNINative.zEncodingTextJavascript()) + + @Throws(JniBindingError::class) + public fun zEncodingTextMarkdown(): ZEncoding = + ZEncoding(JNINative.zEncodingTextMarkdown()) + + @Throws(JniBindingError::class) + public fun zEncodingTextCsv(): ZEncoding = + ZEncoding(JNINative.zEncodingTextCsv()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationSql(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationSql()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationCoapPayload(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationCoapPayload()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationJsonPatchJson(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationJsonPatchJson()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationJsonSeq(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationJsonSeq()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationJsonpath(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationJsonpath()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationJwt(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationJwt()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationMp4(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationMp4()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationSoapXml(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationSoapXml()) + + @Throws(JniBindingError::class) + public fun zEncodingApplicationYang(): ZEncoding = + ZEncoding(JNINative.zEncodingApplicationYang()) + + @Throws(JniBindingError::class) + public fun zEncodingAudioAac(): ZEncoding = + ZEncoding(JNINative.zEncodingAudioAac()) + + @Throws(JniBindingError::class) + public fun zEncodingAudioFlac(): ZEncoding = + ZEncoding(JNINative.zEncodingAudioFlac()) + + @Throws(JniBindingError::class) + public fun zEncodingAudioMp4(): ZEncoding = + ZEncoding(JNINative.zEncodingAudioMp4()) + + @Throws(JniBindingError::class) + public fun zEncodingAudioOgg(): ZEncoding = + ZEncoding(JNINative.zEncodingAudioOgg()) + + @Throws(JniBindingError::class) + public fun zEncodingAudioVorbis(): ZEncoding = + ZEncoding(JNINative.zEncodingAudioVorbis()) + + @Throws(JniBindingError::class) + public fun zEncodingVideoH261(): ZEncoding = + ZEncoding(JNINative.zEncodingVideoH261()) + + @Throws(JniBindingError::class) + public fun zEncodingVideoH263(): ZEncoding = + ZEncoding(JNINative.zEncodingVideoH263()) + + @Throws(JniBindingError::class) + public fun zEncodingVideoH264(): ZEncoding = + ZEncoding(JNINative.zEncodingVideoH264()) + + @Throws(JniBindingError::class) + public fun zEncodingVideoH265(): ZEncoding = + ZEncoding(JNINative.zEncodingVideoH265()) + + @Throws(JniBindingError::class) + public fun zEncodingVideoH266(): ZEncoding = + ZEncoding(JNINative.zEncodingVideoH266()) + + @Throws(JniBindingError::class) + public fun zEncodingVideoMp4(): ZEncoding = + ZEncoding(JNINative.zEncodingVideoMp4()) + + @Throws(JniBindingError::class) + public fun zEncodingVideoOgg(): ZEncoding = + ZEncoding(JNINative.zEncodingVideoOgg()) + + @Throws(JniBindingError::class) + public fun zEncodingVideoRaw(): ZEncoding = + ZEncoding(JNINative.zEncodingVideoRaw()) + + @Throws(JniBindingError::class) + public fun zEncodingVideoVp8(): ZEncoding = + ZEncoding(JNINative.zEncodingVideoVp8()) + + @Throws(JniBindingError::class) + public fun zEncodingVideoVp9(): ZEncoding = + ZEncoding(JNINative.zEncodingVideoVp9()) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/ZZBytes.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/ZZBytes.kt new file mode 100644 index 00000000..c154e341 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/bytes/ZZBytes.kt @@ -0,0 +1,53 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.bytes + +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZZBytes`. */ +public class ZZBytes(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZZBytes { + val p = ptr + ptr = 0L + return ZZBytes(p) + } + + @Throws(JniBindingError::class) + public fun zZbytesToBytes(): ByteArray { + return withSortedHandleLocks(this) { + val z_ptr = this.ptr + if (z_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zZbytesToBytes(z_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zZbytesClone(): ZZBytes { + return withSortedHandleLocks(this) { + val z_ptr = this.ptr + if (z_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZZBytes(JNINative.zZbytesClone(z_ptr)) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + + @Throws(JniBindingError::class) + public fun zZbytesFromVec(bytes: ByteArray): ZZBytes = + ZZBytes(JNINative.zZbytesFromVec(bytes)) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/Callback.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/Callback.kt new file mode 100644 index 00000000..9d3671c4 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/Callback.kt @@ -0,0 +1,6 @@ +// Auto-generated by JniGen - do not edit by hand. +package io.zenoh.jni.callbacks + +public fun interface Callback { + fun run() +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/HelloCallback.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/HelloCallback.kt new file mode 100644 index 00000000..d65afb5c --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/HelloCallback.kt @@ -0,0 +1,13 @@ +// Auto-generated by JniGen - do not edit by hand. +package io.zenoh.jni.callbacks + +import io.zenoh.jni.config.WhatAmI +import io.zenoh.jni.config.ZenohId + +public fun interface HelloCallback { + fun run( + p0_whatami: Int, + p0_zid: ByteArray, + p0_locators: List, + ) +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/QueryCallback.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/QueryCallback.kt new file mode 100644 index 00000000..705e85c2 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/QueryCallback.kt @@ -0,0 +1,24 @@ +// Auto-generated by JniGen - do not edit by hand. +package io.zenoh.jni.callbacks + +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZBytes +import io.zenoh.jni.keyexpr.KeyExpr +import io.zenoh.jni.keyexpr.ZKeyExpr +import io.zenoh.jni.query.ReplyKeyExpr +import io.zenoh.jni.query.ZQuery + +public fun interface QueryCallback { + fun run( + p0_keyExpr_keyExprString: String, + p0_keyExpr_keyExprNative: Long, + p0_parameters: String, + p0_payload: ByteArray?, + p0_encoding__present: Boolean, + p0_encoding_id: Int, + p0_encoding_schema: String?, + p0_attachment: ByteArray?, + p0_acceptsReplies: Int, + p0_query: Long, + ) +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ReplyCallback.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ReplyCallback.kt new file mode 100644 index 00000000..f474a435 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ReplyCallback.kt @@ -0,0 +1,38 @@ +// Auto-generated by JniGen - do not edit by hand. +package io.zenoh.jni.callbacks + +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZBytes +import io.zenoh.jni.config.ZenohId +import io.zenoh.jni.keyexpr.KeyExpr +import io.zenoh.jni.keyexpr.ZKeyExpr +import io.zenoh.jni.qos.CongestionControl +import io.zenoh.jni.qos.Priority +import io.zenoh.jni.sample.Sample +import io.zenoh.jni.sample.SampleKind +import io.zenoh.jni.time.Timestamp + +public fun interface ReplyCallback { + fun run( + p0_replierZid: ByteArray?, + p0_replierEid: Int, + p0_sample__present: Boolean, + p0_sample_keyExpr_keyExprString: String?, + p0_sample_keyExpr_keyExprNative: Long, + p0_sample_payload: ByteArray?, + p0_sample_encoding_id: Int, + p0_sample_encoding_schema: String?, + p0_sample_kind: Int, + p0_sample_timestamp__present: Boolean, + p0_sample_timestamp_ntp64: Long, + p0_sample_timestamp_id: ByteArray?, + p0_sample_express: Boolean, + p0_sample_priority: Int, + p0_sample_congestionControl: Int, + p0_sample_attachment: ByteArray?, + p0_errorPayload: ByteArray?, + p0_errorEncoding__present: Boolean, + p0_errorEncoding_id: Int, + p0_errorEncoding_schema: String?, + ) +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/SampleCallback.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/SampleCallback.kt new file mode 100644 index 00000000..4c1ac9c4 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/SampleCallback.kt @@ -0,0 +1,29 @@ +// Auto-generated by JniGen - do not edit by hand. +package io.zenoh.jni.callbacks + +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZBytes +import io.zenoh.jni.keyexpr.KeyExpr +import io.zenoh.jni.keyexpr.ZKeyExpr +import io.zenoh.jni.qos.CongestionControl +import io.zenoh.jni.qos.Priority +import io.zenoh.jni.sample.SampleKind +import io.zenoh.jni.time.Timestamp + +public fun interface SampleCallback { + fun run( + p0_keyExpr_keyExprString: String, + p0_keyExpr_keyExprNative: Long, + p0_payload: ByteArray, + p0_encoding_id: Int, + p0_encoding_schema: String?, + p0_kind: Int, + p0_timestamp__present: Boolean, + p0_timestamp_ntp64: Long, + p0_timestamp_id: ByteArray?, + p0_express: Boolean, + p0_priority: Int, + p0_congestionControl: Int, + p0_attachment: ByteArray?, + ) +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZHelloCallback.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZHelloCallback.kt new file mode 100644 index 00000000..b23082cb --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZHelloCallback.kt @@ -0,0 +1,10 @@ +// Auto-generated by JniGen - do not edit by hand. +package io.zenoh.jni.callbacks + +import io.zenoh.jni.scouting.ZHello + +public fun interface ZHelloCallback { + fun run( + p0: ZHello, + ) +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZQueryCallback.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZQueryCallback.kt new file mode 100644 index 00000000..7eb7f813 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZQueryCallback.kt @@ -0,0 +1,10 @@ +// Auto-generated by JniGen - do not edit by hand. +package io.zenoh.jni.callbacks + +import io.zenoh.jni.query.ZQuery + +public fun interface ZQueryCallback { + fun run( + p0: ZQuery, + ) +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZReplyCallback.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZReplyCallback.kt new file mode 100644 index 00000000..312e1d2a --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZReplyCallback.kt @@ -0,0 +1,10 @@ +// Auto-generated by JniGen - do not edit by hand. +package io.zenoh.jni.callbacks + +import io.zenoh.jni.query.ZReply + +public fun interface ZReplyCallback { + fun run( + p0: ZReply, + ) +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZSampleCallback.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZSampleCallback.kt new file mode 100644 index 00000000..46374a88 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/callbacks/ZSampleCallback.kt @@ -0,0 +1,10 @@ +// Auto-generated by JniGen - do not edit by hand. +package io.zenoh.jni.callbacks + +import io.zenoh.jni.sample.ZSample + +public fun interface ZSampleCallback { + fun run( + p0: ZSample, + ) +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/JNIconfig.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/JNIconfig.kt new file mode 100644 index 00000000..53d9f1f9 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/JNIconfig.kt @@ -0,0 +1,15 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.config + +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.config.ZZenohId +import io.zenoh.jni.JNINative + +@Throws(JniBindingError::class) +public fun zZenohIdToBytes(z: ZZenohId): ByteArray = + JNINative.zZenohIdToBytes(z.bytes) + +@Throws(JniBindingError::class) +public fun zZenohIdToString(z: ZZenohId): String = + JNINative.zZenohIdToString(z.bytes) + diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/WhatAmI.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/WhatAmI.kt new file mode 100644 index 00000000..612087af --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/WhatAmI.kt @@ -0,0 +1,14 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.config + +/** JVM-side surface for the native Rust `WhatAmI` enum. */ +public enum class WhatAmI(public val value: Int) { + ROUTER(1), + PEER(2), + CLIENT(4); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): WhatAmI = entries.first { it.value == value } + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/ZConfig.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/ZConfig.kt new file mode 100644 index 00000000..0155153c --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/ZConfig.kt @@ -0,0 +1,79 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.config + +import io.zenoh.jni.Error +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZConfig`. */ +public class ZConfig(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZConfig { + val p = ptr + ptr = 0L + return ZConfig(p) + } + + @Throws(Error::class, JniBindingError::class) + public fun zConfigGetJson(key: String): String { + return withSortedHandleLocks(this) { + val c_ptr = this.ptr + if (c_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zConfigGetJson(c_ptr, key) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zConfigInsertJson5(key: String, value: String) { + withSortedHandleLocks(this) { + val c_ptr = this.ptr + if (c_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zConfigInsertJson5(c_ptr, key, value) + } + } + + @Throws(JniBindingError::class) + public fun zConfigClone(): ZConfig { + return withSortedHandleLocks(this) { + val c_ptr = this.ptr + if (c_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZConfig(JNINative.zConfigClone(c_ptr)) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + + @Throws(JniBindingError::class) + public fun zConfigDefault(): ZConfig = + ZConfig(JNINative.zConfigDefault()) + + @Throws(Error::class, JniBindingError::class) + public fun zConfigFromFile(path: String): ZConfig = + ZConfig(JNINative.zConfigFromFile(path)) + + @Throws(Error::class, JniBindingError::class) + public fun zConfigFromJson(s: String): ZConfig = + ZConfig(JNINative.zConfigFromJson(s)) + + @Throws(Error::class, JniBindingError::class) + public fun zConfigFromJson5(s: String): ZConfig = + ZConfig(JNINative.zConfigFromJson5(s)) + + @Throws(Error::class, JniBindingError::class) + public fun zConfigFromYaml(s: String): ZConfig = + ZConfig(JNINative.zConfigFromYaml(s)) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/ZZenohId.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/ZZenohId.kt new file mode 100644 index 00000000..4e83e88a --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/ZZenohId.kt @@ -0,0 +1,7 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.config + +/** Typed by-value wrapper for the native Rust `ZZenohId` (a `Copy` blob carried + * as its raw bytes; `@JvmInline`-erased to `ByteArray` at the JNI boundary). */ +@JvmInline +public value class ZZenohId(public val bytes: ByteArray) diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/ZenohId.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/ZenohId.kt new file mode 100644 index 00000000..65886545 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/config/ZenohId.kt @@ -0,0 +1,15 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.config + +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError + +@JvmInline +public value class ZenohId(val bytes: ByteArray) { + public companion object { + @Throws(JniBindingError::class) + public fun zenohIdToString(bytes: ByteArray): String = + JNINative.zenohIdToString(bytes) + + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/keyexpr/KeyExpr.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/keyexpr/KeyExpr.kt new file mode 100644 index 00000000..e0181779 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/keyexpr/KeyExpr.kt @@ -0,0 +1,58 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.keyexpr + +import io.zenoh.jni.Error +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError + +public data class KeyExpr( + val keyExprString: String, + val keyExprNative: ZKeyExpr?, +) : AutoCloseable { + override fun close() { + keyExprNative?.close() + } + + public companion object { + @JvmStatic + public fun fromParts( + keyExprString: String, + keyExprNative: Long + ): KeyExpr = + KeyExpr(keyExprString, if (keyExprNative == 0L) null else ZKeyExpr(keyExprNative)) + @Throws(Error::class, JniBindingError::class) + public fun keyexprTryFrom(s: String): KeyExpr = + JNINative.keyexprTryFrom(s) + + + @Throws(Error::class, JniBindingError::class) + public fun keyexprAutocanonize(s: String): KeyExpr = + JNINative.keyexprAutocanonize(s) + + + @Throws(Error::class, JniBindingError::class) + public fun keyexprIntersects(a: KeyExpr, b: KeyExpr): Boolean = + JNINative.keyexprIntersects(a, b) + + + @Throws(Error::class, JniBindingError::class) + public fun keyexprIncludes(a: KeyExpr, b: KeyExpr): Boolean = + JNINative.keyexprIncludes(a, b) + + + @Throws(Error::class, JniBindingError::class) + public fun keyexprRelationTo(a: KeyExpr, b: KeyExpr): SetIntersectionLevel = + SetIntersectionLevel.fromInt(JNINative.keyexprRelationTo(a, b)) + + + @Throws(Error::class, JniBindingError::class) + public fun keyexprJoin(a: KeyExpr, b: String): KeyExpr = + JNINative.keyexprJoin(a, b) + + + @Throws(Error::class, JniBindingError::class) + public fun keyexprConcat(a: KeyExpr, b: String): KeyExpr = + JNINative.keyexprConcat(a, b) + + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/keyexpr/SetIntersectionLevel.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/keyexpr/SetIntersectionLevel.kt new file mode 100644 index 00000000..8dab179b --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/keyexpr/SetIntersectionLevel.kt @@ -0,0 +1,15 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.keyexpr + +/** JVM-side surface for the native Rust `SetIntersectionLevel` enum. */ +public enum class SetIntersectionLevel(public val value: Int) { + DISJOINT(0), + INTERSECTS(1), + INCLUDES(2), + EQUALS(3); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): SetIntersectionLevel = entries.first { it.value == value } + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/keyexpr/ZKeyExpr.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/keyexpr/ZKeyExpr.kt new file mode 100644 index 00000000..e98b5e2d --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/keyexpr/ZKeyExpr.kt @@ -0,0 +1,109 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.keyexpr + +import io.zenoh.jni.Error +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZKeyExpr`. */ +public class ZKeyExpr(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZKeyExpr { + val p = ptr + ptr = 0L + return ZKeyExpr(p) + } + + @Throws(JniBindingError::class) + public fun zKeyexprIntersects(b: ZKeyExpr): Boolean { + return withSortedHandleLocks(this, b) { + val a_ptr = this.ptr + if (a_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val b_ptr = b.ptr + if (b_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zKeyexprIntersects(a_ptr, b_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zKeyexprIncludes(b: ZKeyExpr): Boolean { + return withSortedHandleLocks(this, b) { + val a_ptr = this.ptr + if (a_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val b_ptr = b.ptr + if (b_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zKeyexprIncludes(a_ptr, b_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zKeyexprRelationTo(b: ZKeyExpr): SetIntersectionLevel { + return withSortedHandleLocks(this, b) { + val a_ptr = this.ptr + if (a_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val b_ptr = b.ptr + if (b_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + SetIntersectionLevel.fromInt(JNINative.zKeyexprRelationTo(a_ptr, b_ptr)) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zKeyexprJoin(b: String): ZKeyExpr { + return withSortedHandleLocks(this) { + val a_ptr = this.ptr + if (a_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZKeyExpr(JNINative.zKeyexprJoin(a_ptr, b)) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zKeyexprConcat(b: String): ZKeyExpr { + return withSortedHandleLocks(this) { + val a_ptr = this.ptr + if (a_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZKeyExpr(JNINative.zKeyexprConcat(a_ptr, b)) + } + } + + @Throws(JniBindingError::class) + public fun zKeyexprClone(): ZKeyExpr { + return withSortedHandleLocks(this) { + val ke_ptr = this.ptr + if (ke_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZKeyExpr(JNINative.zKeyexprClone(ke_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zKeyexprToString(): String { + return withSortedHandleLocks(this) { + val ke_ptr = this.ptr + if (ke_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zKeyexprToString(ke_ptr) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + + @Throws(Error::class, JniBindingError::class) + public fun zKeyexprTryFrom(s: String): ZKeyExpr = + ZKeyExpr(JNINative.zKeyexprTryFrom(s)) + + @Throws(Error::class, JniBindingError::class) + public fun zKeyexprAutocanonize(s: String): ZKeyExpr = + ZKeyExpr(JNINative.zKeyexprAutocanonize(s)) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/liveliness/ZLivelinessToken.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/liveliness/ZLivelinessToken.kt new file mode 100644 index 00000000..7622ca10 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/liveliness/ZLivelinessToken.kt @@ -0,0 +1,28 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.liveliness + +import io.zenoh.jni.NativeHandle + +/** Typed handle for a native Zenoh `ZLivelinessToken`. */ +public class ZLivelinessToken(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZLivelinessToken { + val p = ptr + ptr = 0L + return ZLivelinessToken(p) + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/logger/JNIlogger.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/logger/JNIlogger.kt new file mode 100644 index 00000000..05ed2c78 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/logger/JNIlogger.kt @@ -0,0 +1,17 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.logger + +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.JNINative + +@Throws(JniBindingError::class) +public fun initAndroidLogs(filter: String) = + JNINative.initAndroidLogs(filter) + +public fun tryInitZenohLogsFromEnv() = + JNINative.tryInitZenohLogsFromEnv() + +@Throws(JniBindingError::class) +public fun initZenohLogsFromEnvOr(fallbackFilter: String) = + JNINative.initZenohLogsFromEnvOr(fallbackFilter) + diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/pubsub/ZPublisher.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/pubsub/ZPublisher.kt new file mode 100644 index 00000000..f3e640b4 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/pubsub/ZPublisher.kt @@ -0,0 +1,94 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.pubsub + +import io.zenoh.jni.Error +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZBytes +import io.zenoh.jni.bytes.ZEncoding +import io.zenoh.jni.bytes.ZZBytes +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZPublisher`. */ +public class ZPublisher(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZPublisher { + val p = ptr + ptr = 0L + return ZPublisher(p) + } + + @Throws(Error::class, JniBindingError::class) + public fun zPublisherPut(payload: ZZBytes, encoding: ZEncoding?, attachment: ZZBytes) { + val __locks = ArrayList() + __locks.add(this) + __locks.add(payload) + encoding?.let { __locks.add(it) } + __locks.add(attachment) + withSortedHandleLocks(__locks) { + val publisher_ptr = this.ptr + if (publisher_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val payload_ptr = payload.ptr + if (payload_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val encoding_ptr = encoding?.ptr ?: 0L + if (encoding != null && encoding_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val attachment_ptr = attachment.ptr + if (attachment_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zPublisherPut(publisher_ptr, payload_ptr, encoding_ptr, attachment_ptr) + } finally { + payload.ptr = 0L + attachment.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zPublisherDelete(attachment: ZZBytes) { + withSortedHandleLocks(this, attachment) { + val publisher_ptr = this.ptr + if (publisher_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val attachment_ptr = attachment.ptr + if (attachment_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zPublisherDelete(publisher_ptr, attachment_ptr) + } finally { + attachment.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun publisherPut(payload: ZBytes, encoding: Encoding?, attachment: ZBytes?) { + withSortedHandleLocks(this) { + val publisher_ptr = this.ptr + if (publisher_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.publisherPut(publisher_ptr, payload.bytes, encoding != null, encoding?.id ?: 0, encoding?.schema, attachment?.bytes) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun publisherDelete(attachment: ZBytes?) { + withSortedHandleLocks(this) { + val publisher_ptr = this.ptr + if (publisher_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.publisherDelete(publisher_ptr, attachment?.bytes) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/pubsub/ZSubscriber.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/pubsub/ZSubscriber.kt new file mode 100644 index 00000000..43ab0f77 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/pubsub/ZSubscriber.kt @@ -0,0 +1,28 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.pubsub + +import io.zenoh.jni.NativeHandle + +/** Typed handle for a native Zenoh `ZSubscriber`. */ +public class ZSubscriber(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZSubscriber { + val p = ptr + ptr = 0L + return ZSubscriber(p) + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/qos/CongestionControl.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/qos/CongestionControl.kt new file mode 100644 index 00000000..bddceafe --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/qos/CongestionControl.kt @@ -0,0 +1,14 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.qos + +/** JVM-side surface for the native Rust `CongestionControl` enum. */ +public enum class CongestionControl(public val value: Int) { + DROP(0), + BLOCK(1), + BLOCK_FIRST(2); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): CongestionControl = entries.first { it.value == value } + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/qos/Priority.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/qos/Priority.kt new file mode 100644 index 00000000..90597742 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/qos/Priority.kt @@ -0,0 +1,18 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.qos + +/** JVM-side surface for the native Rust `Priority` enum. */ +public enum class Priority(public val value: Int) { + REAL_TIME(1), + INTERACTIVE_HIGH(2), + INTERACTIVE_LOW(3), + DATA_HIGH(4), + DATA(5), + DATA_LOW(6), + BACKGROUND(7); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): Priority = entries.first { it.value == value } + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/qos/Reliability.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/qos/Reliability.kt new file mode 100644 index 00000000..fca147a1 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/qos/Reliability.kt @@ -0,0 +1,13 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.qos + +/** JVM-side surface for the native Rust `Reliability` enum. */ +public enum class Reliability(public val value: Int) { + BEST_EFFORT(0), + RELIABLE(1); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): Reliability = entries.first { it.value == value } + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ConsolidationMode.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ConsolidationMode.kt new file mode 100644 index 00000000..eec68606 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ConsolidationMode.kt @@ -0,0 +1,15 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.query + +/** JVM-side surface for the native Rust `ConsolidationMode` enum. */ +public enum class ConsolidationMode(public val value: Int) { + AUTO(0), + NONE(1), + MONOTONIC(2), + LATEST(3); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): ConsolidationMode = entries.first { it.value == value } + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/Query.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/Query.kt new file mode 100644 index 00000000..94b4a06d --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/Query.kt @@ -0,0 +1,38 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.query + +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZBytes +import io.zenoh.jni.keyexpr.KeyExpr +import io.zenoh.jni.keyexpr.ZKeyExpr + +public data class Query( + val keyExpr: KeyExpr, + val parameters: String, + val payload: ZBytes?, + val encoding: Encoding?, + val attachment: ZBytes?, + val acceptsReplies: ReplyKeyExpr, + val query: ZQuery, +) : AutoCloseable { + override fun close() { + query.close() + } + + public companion object { + @JvmStatic + public fun fromParts( + keyExpr_keyExprString: String, + keyExpr_keyExprNative: Long, + parameters: String, + payload: ByteArray?, + encoding__present: Boolean, + encoding_id: Int, + encoding_schema: String?, + attachment: ByteArray?, + acceptsReplies: Int, + query: Long + ): Query = + Query(KeyExpr.fromParts(keyExpr_keyExprString, keyExpr_keyExprNative), parameters, payload?.let { ZBytes(it) }, if (encoding__present) Encoding.fromParts(encoding_id, encoding_schema) else null, attachment?.let { ZBytes(it) }, ReplyKeyExpr.fromInt(acceptsReplies), ZQuery(query)) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/QueryTarget.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/QueryTarget.kt new file mode 100644 index 00000000..dbef39f5 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/QueryTarget.kt @@ -0,0 +1,14 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.query + +/** JVM-side surface for the native Rust `QueryTarget` enum. */ +public enum class QueryTarget(public val value: Int) { + BEST_MATCHING(0), + ALL(1), + ALL_COMPLETE(2); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): QueryTarget = entries.first { it.value == value } + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/Reply.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/Reply.kt new file mode 100644 index 00000000..1a838bd7 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/Reply.kt @@ -0,0 +1,48 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.query + +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZBytes +import io.zenoh.jni.config.ZenohId +import io.zenoh.jni.keyexpr.KeyExpr +import io.zenoh.jni.keyexpr.ZKeyExpr +import io.zenoh.jni.qos.CongestionControl +import io.zenoh.jni.qos.Priority +import io.zenoh.jni.sample.Sample +import io.zenoh.jni.sample.SampleKind +import io.zenoh.jni.time.Timestamp + +public data class Reply( + val replierZid: ZenohId?, + val replierEid: Int, + val sample: Sample?, + val errorPayload: ZBytes?, + val errorEncoding: Encoding?, +) { + public companion object { + @JvmStatic + public fun fromParts( + replierZid: ByteArray?, + replierEid: Int, + sample__present: Boolean, + sample_keyExpr_keyExprString: String?, + sample_keyExpr_keyExprNative: Long, + sample_payload: ByteArray?, + sample_encoding_id: Int, + sample_encoding_schema: String?, + sample_kind: Int, + sample_timestamp__present: Boolean, + sample_timestamp_ntp64: Long, + sample_timestamp_id: ByteArray?, + sample_express: Boolean, + sample_priority: Int, + sample_congestionControl: Int, + sample_attachment: ByteArray?, + errorPayload: ByteArray?, + errorEncoding__present: Boolean, + errorEncoding_id: Int, + errorEncoding_schema: String? + ): Reply = + Reply(replierZid?.let { ZenohId(it) }, replierEid, if (sample__present) Sample.fromParts(sample_keyExpr_keyExprString!!, sample_keyExpr_keyExprNative, sample_payload!!, sample_encoding_id, sample_encoding_schema, sample_kind, sample_timestamp__present, sample_timestamp_ntp64, sample_timestamp_id, sample_express, sample_priority, sample_congestionControl, sample_attachment) else null, errorPayload?.let { ZBytes(it) }, if (errorEncoding__present) Encoding.fromParts(errorEncoding_id, errorEncoding_schema) else null) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ReplyKeyExpr.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ReplyKeyExpr.kt new file mode 100644 index 00000000..908e2300 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ReplyKeyExpr.kt @@ -0,0 +1,13 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.query + +/** JVM-side surface for the native Rust `ReplyKeyExpr` enum. */ +public enum class ReplyKeyExpr(public val value: Int) { + ANY(0), + MATCHING_QUERY(1); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): ReplyKeyExpr = entries.first { it.value == value } + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZQuerier.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZQuerier.kt new file mode 100644 index 00000000..ed9b185d --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZQuerier.kt @@ -0,0 +1,73 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.query + +import io.zenoh.jni.Error +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZBytes +import io.zenoh.jni.bytes.ZEncoding +import io.zenoh.jni.bytes.ZZBytes +import io.zenoh.jni.callbacks.Callback +import io.zenoh.jni.callbacks.ReplyCallback +import io.zenoh.jni.callbacks.ZReplyCallback +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZQuerier`. */ +public class ZQuerier(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZQuerier { + val p = ptr + ptr = 0L + return ZQuerier(p) + } + + @Throws(Error::class, JniBindingError::class) + public fun zQuerierGet(parameters: String?, payload: ZZBytes, encoding: ZEncoding?, attachment: ZZBytes, callback: ZReplyCallback, onClose: Callback) { + val __locks = ArrayList() + __locks.add(this) + __locks.add(payload) + encoding?.let { __locks.add(it) } + __locks.add(attachment) + withSortedHandleLocks(__locks) { + val querier_ptr = this.ptr + if (querier_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val payload_ptr = payload.ptr + if (payload_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val encoding_ptr = encoding?.ptr ?: 0L + if (encoding != null && encoding_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val attachment_ptr = attachment.ptr + if (attachment_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zQuerierGet(querier_ptr, parameters, payload_ptr, encoding_ptr, attachment_ptr, callback, onClose) + } finally { + payload.ptr = 0L + attachment.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun querierGet(parameters: String?, payload: ZBytes?, encoding: Encoding?, attachment: ZBytes?, callback: ReplyCallback, onClose: Callback) { + withSortedHandleLocks(this) { + val querier_ptr = this.ptr + if (querier_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.querierGet(querier_ptr, parameters, payload?.bytes, encoding != null, encoding?.id ?: 0, encoding?.schema, attachment?.bytes, callback, onClose) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZQuery.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZQuery.kt new file mode 100644 index 00000000..9d3da0f5 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZQuery.kt @@ -0,0 +1,192 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.query + +import io.zenoh.jni.Error +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZBytes +import io.zenoh.jni.bytes.ZEncoding +import io.zenoh.jni.bytes.ZZBytes +import io.zenoh.jni.keyexpr.KeyExpr +import io.zenoh.jni.keyexpr.ZKeyExpr +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZQuery`. */ +public class ZQuery(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZQuery { + val p = ptr + ptr = 0L + return ZQuery(p) + } + + @Throws(Error::class, JniBindingError::class) + public fun zQueryReplySuccess(keyExpr: ZKeyExpr, payload: ZZBytes, encoding: ZEncoding?, timestampNtp64: Long?, attachment: ZZBytes, express: Boolean?) { + val __locks = ArrayList() + __locks.add(this) + __locks.add(keyExpr) + __locks.add(payload) + encoding?.let { __locks.add(it) } + __locks.add(attachment) + withSortedHandleLocks(__locks) { + val query_ptr = this.ptr + if (query_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val payload_ptr = payload.ptr + if (payload_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val encoding_ptr = encoding?.ptr ?: 0L + if (encoding != null && encoding_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val attachment_ptr = attachment.ptr + if (attachment_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zQueryReplySuccess(query_ptr, keyExpr_ptr, payload_ptr, encoding_ptr, timestampNtp64, attachment_ptr, express) + } finally { + payload.ptr = 0L + attachment.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zQueryReplyError(payload: ZZBytes, encoding: ZEncoding?) { + val __locks = ArrayList() + __locks.add(this) + __locks.add(payload) + encoding?.let { __locks.add(it) } + withSortedHandleLocks(__locks) { + val query_ptr = this.ptr + if (query_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val payload_ptr = payload.ptr + if (payload_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val encoding_ptr = encoding?.ptr ?: 0L + if (encoding != null && encoding_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zQueryReplyError(query_ptr, payload_ptr, encoding_ptr) + } finally { + payload.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zQueryReplyDelete(keyExpr: ZKeyExpr, timestampNtp64: Long?, attachment: ZZBytes, express: Boolean?) { + withSortedHandleLocks(this, keyExpr, attachment) { + val query_ptr = this.ptr + if (query_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val attachment_ptr = attachment.ptr + if (attachment_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zQueryReplyDelete(query_ptr, keyExpr_ptr, timestampNtp64, attachment_ptr, express) + } finally { + attachment.ptr = 0L + } + } + } + + @Throws(JniBindingError::class) + public fun zQueryKeyexpr(): ZKeyExpr { + return withSortedHandleLocks(this) { + val q_ptr = this.ptr + if (q_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZKeyExpr(JNINative.zQueryKeyexpr(q_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zQueryParameters(): String { + return withSortedHandleLocks(this) { + val q_ptr = this.ptr + if (q_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zQueryParameters(q_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zQueryPayload(): ZZBytes? { + return withSortedHandleLocks(this) { + val q_ptr = this.ptr + if (q_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zQueryPayload(q_ptr).let { if (it == 0L) null else ZZBytes(it) } + } + } + + @Throws(JniBindingError::class) + public fun zQueryEncoding(): ZEncoding? { + return withSortedHandleLocks(this) { + val q_ptr = this.ptr + if (q_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zQueryEncoding(q_ptr).let { if (it == 0L) null else ZEncoding(it) } + } + } + + @Throws(JniBindingError::class) + public fun zQueryExpand(): Query { + return withSortedHandleLocks(this) { + val query_ptr = this.ptr + if (query_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zQueryExpand(query_ptr) + } finally { + ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun queryReplySuccess(keyExpr: KeyExpr, payload: ZBytes, encoding: Encoding?, timestampNtp64: Long?, attachment: ZBytes?, express: Boolean?) { + withSortedHandleLocks(this) { + val query_ptr = this.ptr + if (query_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.queryReplySuccess(query_ptr, keyExpr, payload.bytes, encoding != null, encoding?.id ?: 0, encoding?.schema, timestampNtp64, attachment?.bytes, express) + } finally { + ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun queryReplyError(payload: ZBytes, encoding: Encoding?) { + withSortedHandleLocks(this) { + val query_ptr = this.ptr + if (query_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.queryReplyError(query_ptr, payload.bytes, encoding != null, encoding?.id ?: 0, encoding?.schema) + } finally { + ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun queryReplyDelete(keyExpr: KeyExpr, timestampNtp64: Long?, attachment: ZBytes?, express: Boolean?) { + withSortedHandleLocks(this) { + val query_ptr = this.ptr + if (query_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.queryReplyDelete(query_ptr, keyExpr, timestampNtp64, attachment?.bytes, express) + } finally { + ptr = 0L + } + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZQueryable.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZQueryable.kt new file mode 100644 index 00000000..f39646b6 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZQueryable.kt @@ -0,0 +1,28 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.query + +import io.zenoh.jni.NativeHandle + +/** Typed handle for a native Zenoh `ZQueryable`. */ +public class ZQueryable(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZQueryable { + val p = ptr + ptr = 0L + return ZQueryable(p) + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZReply.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZReply.kt new file mode 100644 index 00000000..7e8b0bed --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/query/ZReply.kt @@ -0,0 +1,108 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.query + +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.bytes.ZEncoding +import io.zenoh.jni.bytes.ZZBytes +import io.zenoh.jni.config.ZZenohId +import io.zenoh.jni.config.ZenohId +import io.zenoh.jni.sample.ZSample +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZReply`. */ +public class ZReply(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZReply { + val p = ptr + ptr = 0L + return ZReply(p) + } + + @Throws(JniBindingError::class) + public fun replyReplierZid(): ZenohId? { + return withSortedHandleLocks(this) { + val r_ptr = this.ptr + if (r_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.replyReplierZid(r_ptr)?.let { ZenohId(it) } + } + } + + @Throws(JniBindingError::class) + public fun zReplyReplierZid(): ZZenohId? { + return withSortedHandleLocks(this) { + val r_ptr = this.ptr + if (r_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zReplyReplierZid(r_ptr)?.let { ZZenohId(it) } + } + } + + @Throws(JniBindingError::class) + public fun zReplyReplierEid(): Int { + return withSortedHandleLocks(this) { + val r_ptr = this.ptr + if (r_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zReplyReplierEid(r_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zReplyIsOk(): Boolean { + return withSortedHandleLocks(this) { + val r_ptr = this.ptr + if (r_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zReplyIsOk(r_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zReplySample(): ZSample? { + return withSortedHandleLocks(this) { + val r_ptr = this.ptr + if (r_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zReplySample(r_ptr).let { if (it == 0L) null else ZSample(it) } + } + } + + @Throws(JniBindingError::class) + public fun zReplyErrorPayload(): ZZBytes? { + return withSortedHandleLocks(this) { + val r_ptr = this.ptr + if (r_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zReplyErrorPayload(r_ptr).let { if (it == 0L) null else ZZBytes(it) } + } + } + + @Throws(JniBindingError::class) + public fun zReplyErrorEncoding(): ZEncoding? { + return withSortedHandleLocks(this) { + val r_ptr = this.ptr + if (r_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zReplyErrorEncoding(r_ptr).let { if (it == 0L) null else ZEncoding(it) } + } + } + + @Throws(JniBindingError::class) + public fun zReplyExpand(): Reply { + return withSortedHandleLocks(this) { + val r_ptr = this.ptr + if (r_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zReplyExpand(r_ptr) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/sample/Sample.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/sample/Sample.kt new file mode 100644 index 00000000..ec12dce8 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/sample/Sample.kt @@ -0,0 +1,42 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.sample + +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZBytes +import io.zenoh.jni.keyexpr.KeyExpr +import io.zenoh.jni.keyexpr.ZKeyExpr +import io.zenoh.jni.qos.CongestionControl +import io.zenoh.jni.qos.Priority +import io.zenoh.jni.time.Timestamp + +public data class Sample( + val keyExpr: KeyExpr, + val payload: ZBytes, + val encoding: Encoding, + val kind: SampleKind, + val timestamp: Timestamp?, + val express: Boolean, + val priority: Priority, + val congestionControl: CongestionControl, + val attachment: ZBytes?, +) { + public companion object { + @JvmStatic + public fun fromParts( + keyExpr_keyExprString: String, + keyExpr_keyExprNative: Long, + payload: ByteArray, + encoding_id: Int, + encoding_schema: String?, + kind: Int, + timestamp__present: Boolean, + timestamp_ntp64: Long, + timestamp_id: ByteArray?, + express: Boolean, + priority: Int, + congestionControl: Int, + attachment: ByteArray? + ): Sample = + Sample(KeyExpr.fromParts(keyExpr_keyExprString, keyExpr_keyExprNative), ZBytes(payload), Encoding.fromParts(encoding_id, encoding_schema), SampleKind.fromInt(kind), if (timestamp__present) Timestamp.fromParts(timestamp_ntp64, timestamp_id!!) else null, express, Priority.fromInt(priority), CongestionControl.fromInt(congestionControl), attachment?.let { ZBytes(it) }) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/sample/SampleKind.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/sample/SampleKind.kt new file mode 100644 index 00000000..f71eccc0 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/sample/SampleKind.kt @@ -0,0 +1,13 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.sample + +/** JVM-side surface for the native Rust `SampleKind` enum. */ +public enum class SampleKind(public val value: Int) { + PUT(0), + DELETE(1); + + public companion object { + @JvmStatic + public fun fromInt(value: Int): SampleKind = entries.first { it.value == value } + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/sample/ZSample.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/sample/ZSample.kt new file mode 100644 index 00000000..e3c79a56 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/sample/ZSample.kt @@ -0,0 +1,127 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.sample + +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.bytes.ZEncoding +import io.zenoh.jni.bytes.ZZBytes +import io.zenoh.jni.keyexpr.ZKeyExpr +import io.zenoh.jni.qos.CongestionControl +import io.zenoh.jni.qos.Priority +import io.zenoh.jni.time.ZTimestamp +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZSample`. */ +public class ZSample(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZSample { + val p = ptr + ptr = 0L + return ZSample(p) + } + + @Throws(JniBindingError::class) + public fun zSampleKeyExpr(): ZKeyExpr { + return withSortedHandleLocks(this) { + val s_ptr = this.ptr + if (s_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZKeyExpr(JNINative.zSampleKeyExpr(s_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zSamplePayload(): ZZBytes { + return withSortedHandleLocks(this) { + val s_ptr = this.ptr + if (s_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZZBytes(JNINative.zSamplePayload(s_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zSampleEncoding(): ZEncoding { + return withSortedHandleLocks(this) { + val s_ptr = this.ptr + if (s_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZEncoding(JNINative.zSampleEncoding(s_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zSampleKind(): SampleKind { + return withSortedHandleLocks(this) { + val s_ptr = this.ptr + if (s_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + SampleKind.fromInt(JNINative.zSampleKind(s_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zSampleTimestamp(): ZTimestamp? { + return withSortedHandleLocks(this) { + val s_ptr = this.ptr + if (s_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zSampleTimestamp(s_ptr).let { if (it == 0L) null else ZTimestamp(it) } + } + } + + @Throws(JniBindingError::class) + public fun zSampleExpress(): Boolean { + return withSortedHandleLocks(this) { + val s_ptr = this.ptr + if (s_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zSampleExpress(s_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zSamplePriority(): Priority { + return withSortedHandleLocks(this) { + val s_ptr = this.ptr + if (s_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + Priority.fromInt(JNINative.zSamplePriority(s_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zSampleCongestionControl(): CongestionControl { + return withSortedHandleLocks(this) { + val s_ptr = this.ptr + if (s_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + CongestionControl.fromInt(JNINative.zSampleCongestionControl(s_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zSampleAttachment(): ZZBytes? { + return withSortedHandleLocks(this) { + val s_ptr = this.ptr + if (s_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zSampleAttachment(s_ptr).let { if (it == 0L) null else ZZBytes(it) } + } + } + + @Throws(JniBindingError::class) + public fun zSampleExpand(): Sample { + return withSortedHandleLocks(this) { + val s_ptr = this.ptr + if (s_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zSampleExpand(s_ptr) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/Hello.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/Hello.kt new file mode 100644 index 00000000..aba4dc78 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/Hello.kt @@ -0,0 +1,21 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.scouting + +import io.zenoh.jni.config.WhatAmI +import io.zenoh.jni.config.ZenohId + +public data class Hello( + val whatami: WhatAmI, + val zid: ZenohId, + val locators: List, +) { + public companion object { + @JvmStatic + public fun fromParts( + whatami: Int, + zid: ByteArray, + locators: List + ): Hello = + Hello(WhatAmI.fromInt(whatami), ZenohId(zid), locators) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/JNIscouting.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/JNIscouting.kt new file mode 100644 index 00000000..240cb94e --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/JNIscouting.kt @@ -0,0 +1,36 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.scouting + +import io.zenoh.jni.Error +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.callbacks.Callback +import io.zenoh.jni.callbacks.HelloCallback +import io.zenoh.jni.callbacks.ZHelloCallback +import io.zenoh.jni.config.ZConfig +import io.zenoh.jni.scouting.ZScout +import io.zenoh.jni.withSortedHandleLocks +import io.zenoh.jni.JNINative + +@Throws(Error::class, JniBindingError::class) +public fun zScout(whatami: Int, config: ZConfig?, callback: ZHelloCallback, onClose: Callback): ZScout { + val __locks = ArrayList() + config?.let { __locks.add(it) } + return withSortedHandleLocks(__locks) { + val config_ptr = config?.ptr ?: 0L + if (config != null && config_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZScout(JNINative.zScout(whatami, config_ptr, callback, onClose)) + } +} + +@Throws(Error::class, JniBindingError::class) +public fun scout(whatami: Int, config: ZConfig?, callback: HelloCallback, onClose: Callback): ZScout { + val __locks = ArrayList() + config?.let { __locks.add(it) } + return withSortedHandleLocks(__locks) { + val config_ptr = config?.ptr ?: 0L + if (config != null && config_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZScout(JNINative.scout(whatami, config_ptr, callback, onClose)) + } +} + diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/ZHello.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/ZHello.kt new file mode 100644 index 00000000..cdc00fad --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/ZHello.kt @@ -0,0 +1,70 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.scouting + +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.config.WhatAmI +import io.zenoh.jni.config.ZZenohId +import io.zenoh.jni.config.ZenohId +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZHello`. */ +public class ZHello(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZHello { + val p = ptr + ptr = 0L + return ZHello(p) + } + + @Throws(JniBindingError::class) + public fun zHelloWhatami(): WhatAmI { + return withSortedHandleLocks(this) { + val h_ptr = this.ptr + if (h_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + WhatAmI.fromInt(JNINative.zHelloWhatami(h_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun helloZid(): ZenohId { + return withSortedHandleLocks(this) { + val h_ptr = this.ptr + if (h_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZenohId(JNINative.helloZid(h_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zHelloZid(): ZZenohId { + return withSortedHandleLocks(this) { + val h_ptr = this.ptr + if (h_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZZenohId(JNINative.zHelloZid(h_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zHelloLocators(): List { + return withSortedHandleLocks(this) { + val h_ptr = this.ptr + if (h_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zHelloLocators(h_ptr) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/ZScout.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/ZScout.kt new file mode 100644 index 00000000..5b977579 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/scouting/ZScout.kt @@ -0,0 +1,28 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.scouting + +import io.zenoh.jni.NativeHandle + +/** Typed handle for a native Zenoh `ZScout`. */ +public class ZScout(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZScout { + val p = ptr + ptr = 0L + return ZScout(p) + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/session/ZSession.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/session/ZSession.kt new file mode 100644 index 00000000..3a059176 --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/session/ZSession.kt @@ -0,0 +1,414 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.session + +import io.zenoh.jni.Error +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.bytes.Encoding +import io.zenoh.jni.bytes.ZBytes +import io.zenoh.jni.bytes.ZEncoding +import io.zenoh.jni.bytes.ZZBytes +import io.zenoh.jni.callbacks.Callback +import io.zenoh.jni.callbacks.QueryCallback +import io.zenoh.jni.callbacks.ReplyCallback +import io.zenoh.jni.callbacks.SampleCallback +import io.zenoh.jni.callbacks.ZQueryCallback +import io.zenoh.jni.callbacks.ZReplyCallback +import io.zenoh.jni.callbacks.ZSampleCallback +import io.zenoh.jni.config.ZConfig +import io.zenoh.jni.config.ZZenohId +import io.zenoh.jni.config.ZenohId +import io.zenoh.jni.keyexpr.KeyExpr +import io.zenoh.jni.keyexpr.ZKeyExpr +import io.zenoh.jni.liveliness.ZLivelinessToken +import io.zenoh.jni.pubsub.ZPublisher +import io.zenoh.jni.pubsub.ZSubscriber +import io.zenoh.jni.qos.CongestionControl +import io.zenoh.jni.qos.Priority +import io.zenoh.jni.qos.Reliability +import io.zenoh.jni.query.ConsolidationMode +import io.zenoh.jni.query.QueryTarget +import io.zenoh.jni.query.ReplyKeyExpr +import io.zenoh.jni.query.ZQuerier +import io.zenoh.jni.query.ZQueryable +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZSession`. */ +public class ZSession(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZSession { + val p = ptr + ptr = 0L + return ZSession(p) + } + + @Throws(Error::class, JniBindingError::class) + public fun zSessionDeclarePublisher(keyExpr: ZKeyExpr, congestionControl: CongestionControl?, priority: Priority?, express: Boolean?, reliability: Reliability?): ZPublisher { + return withSortedHandleLocks(this, keyExpr) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + ZPublisher(JNINative.zSessionDeclarePublisher(session_ptr, keyExpr_ptr, congestionControl?.value, priority?.value, express, reliability?.value)) + } finally { + keyExpr.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zSessionPut(keyExpr: ZKeyExpr, payload: ZZBytes, encoding: ZEncoding?, congestionControl: CongestionControl?, priority: Priority?, express: Boolean?, attachment: ZZBytes, reliability: Reliability?) { + val __locks = ArrayList() + __locks.add(this) + __locks.add(keyExpr) + __locks.add(payload) + encoding?.let { __locks.add(it) } + __locks.add(attachment) + withSortedHandleLocks(__locks) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val payload_ptr = payload.ptr + if (payload_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val encoding_ptr = encoding?.ptr ?: 0L + if (encoding != null && encoding_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val attachment_ptr = attachment.ptr + if (attachment_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zSessionPut(session_ptr, keyExpr_ptr, payload_ptr, encoding_ptr, congestionControl?.value, priority?.value, express, attachment_ptr, reliability?.value) + } finally { + payload.ptr = 0L + attachment.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zSessionDelete(keyExpr: ZKeyExpr, congestionControl: CongestionControl?, priority: Priority?, express: Boolean?, attachment: ZZBytes, reliability: Reliability?) { + withSortedHandleLocks(this, keyExpr, attachment) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val attachment_ptr = attachment.ptr + if (attachment_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zSessionDelete(session_ptr, keyExpr_ptr, congestionControl?.value, priority?.value, express, attachment_ptr, reliability?.value) + } finally { + attachment.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zSessionDeclareSubscriber(keyExpr: ZKeyExpr, callback: ZSampleCallback, onClose: Callback): ZSubscriber { + return withSortedHandleLocks(this, keyExpr) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + ZSubscriber(JNINative.zSessionDeclareSubscriber(session_ptr, keyExpr_ptr, callback, onClose)) + } finally { + keyExpr.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun sessionDeclareSubscriber(keyExpr: KeyExpr, callback: SampleCallback, onClose: Callback): ZSubscriber { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZSubscriber(JNINative.sessionDeclareSubscriber(session_ptr, keyExpr, callback, onClose)) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zSessionDeclareQuerier(keyExpr: ZKeyExpr, target: QueryTarget?, consolidation: ConsolidationMode?, congestionControl: CongestionControl?, priority: Priority?, express: Boolean?, timeoutMs: Long?, acceptReplies: ReplyKeyExpr?): ZQuerier { + return withSortedHandleLocks(this, keyExpr) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + ZQuerier(JNINative.zSessionDeclareQuerier(session_ptr, keyExpr_ptr, target?.value, consolidation?.value, congestionControl?.value, priority?.value, express, timeoutMs, acceptReplies?.value)) + } finally { + keyExpr.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zSessionDeclareQueryable(keyExpr: ZKeyExpr, complete: Boolean?, callback: ZQueryCallback, onClose: Callback): ZQueryable { + return withSortedHandleLocks(this, keyExpr) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + ZQueryable(JNINative.zSessionDeclareQueryable(session_ptr, keyExpr_ptr, complete, callback, onClose)) + } finally { + keyExpr.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun sessionDeclareQueryable(keyExpr: KeyExpr, complete: Boolean?, callback: QueryCallback, onClose: Callback): ZQueryable { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZQueryable(JNINative.sessionDeclareQueryable(session_ptr, keyExpr, complete, callback, onClose)) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zSessionDeclareKeyexpr(keyExpr: String): ZKeyExpr { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZKeyExpr(JNINative.zSessionDeclareKeyexpr(session_ptr, keyExpr)) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zSessionUndeclareKeyexpr(keyExpr: ZKeyExpr) { + withSortedHandleLocks(this, keyExpr) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zSessionUndeclareKeyexpr(session_ptr, keyExpr_ptr) + } finally { + keyExpr.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zSessionGet(keyExpr: ZKeyExpr, parameters: String?, timeoutMs: Long?, target: QueryTarget?, consolidation: ConsolidationMode?, acceptReplies: ReplyKeyExpr?, congestionControl: CongestionControl?, priority: Priority?, express: Boolean?, payload: ZZBytes, encoding: ZEncoding?, attachment: ZZBytes, callback: ZReplyCallback, onClose: Callback) { + val __locks = ArrayList() + __locks.add(this) + __locks.add(keyExpr) + __locks.add(payload) + encoding?.let { __locks.add(it) } + __locks.add(attachment) + withSortedHandleLocks(__locks) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val payload_ptr = payload.ptr + if (payload_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val encoding_ptr = encoding?.ptr ?: 0L + if (encoding != null && encoding_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val attachment_ptr = attachment.ptr + if (attachment_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + JNINative.zSessionGet(session_ptr, keyExpr_ptr, parameters, timeoutMs, target?.value, consolidation?.value, acceptReplies?.value, congestionControl?.value, priority?.value, express, payload_ptr, encoding_ptr, attachment_ptr, callback, onClose) + } finally { + payload.ptr = 0L + attachment.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun sessionGet(keyExpr: KeyExpr, parameters: String?, timeoutMs: Long?, target: QueryTarget?, consolidation: ConsolidationMode?, acceptReplies: ReplyKeyExpr?, congestionControl: CongestionControl?, priority: Priority?, express: Boolean?, payload: ZBytes?, encoding: Encoding?, attachment: ZBytes?, callback: ReplyCallback, onClose: Callback) { + withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.sessionGet(session_ptr, keyExpr, parameters, timeoutMs, target?.value, consolidation?.value, acceptReplies?.value, congestionControl?.value, priority?.value, express, payload?.bytes, encoding != null, encoding?.id ?: 0, encoding?.schema, attachment?.bytes, callback, onClose) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun sessionDeclarePublisher(keyExpr: KeyExpr, congestionControl: CongestionControl?, priority: Priority?, express: Boolean?, reliability: Reliability?): ZPublisher { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZPublisher(JNINative.sessionDeclarePublisher(session_ptr, keyExpr, congestionControl?.value, priority?.value, express, reliability?.value)) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun sessionDeclareQuerier(keyExpr: KeyExpr, target: QueryTarget?, consolidation: ConsolidationMode?, congestionControl: CongestionControl?, priority: Priority?, express: Boolean?, timeoutMs: Long?, acceptReplies: ReplyKeyExpr?): ZQuerier { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZQuerier(JNINative.sessionDeclareQuerier(session_ptr, keyExpr, target?.value, consolidation?.value, congestionControl?.value, priority?.value, express, timeoutMs, acceptReplies?.value)) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun sessionPut(keyExpr: KeyExpr, payload: ZBytes, encoding: Encoding?, congestionControl: CongestionControl?, priority: Priority?, express: Boolean?, attachment: ZBytes?, reliability: Reliability?) { + withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.sessionPut(session_ptr, keyExpr, payload.bytes, encoding != null, encoding?.id ?: 0, encoding?.schema, congestionControl?.value, priority?.value, express, attachment?.bytes, reliability?.value) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun sessionDelete(keyExpr: KeyExpr, congestionControl: CongestionControl?, priority: Priority?, express: Boolean?, attachment: ZBytes?, reliability: Reliability?) { + withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.sessionDelete(session_ptr, keyExpr, congestionControl?.value, priority?.value, express, attachment?.bytes, reliability?.value) + } + } + + @Throws(JniBindingError::class) + public fun sessionZid(): ZenohId { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZenohId(JNINative.sessionZid(session_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun sessionPeersZid(): List { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.sessionPeersZid(session_ptr).map { ZenohId(it) } + } + } + + @Throws(JniBindingError::class) + public fun sessionRoutersZid(): List { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.sessionRoutersZid(session_ptr).map { ZenohId(it) } + } + } + + @Throws(JniBindingError::class) + public fun zSessionZid(): ZZenohId { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZZenohId(JNINative.zSessionZid(session_ptr)) + } + } + + @Throws(JniBindingError::class) + public fun zSessionPeersZid(): List { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zSessionPeersZid(session_ptr).map { ZZenohId(it) } + } + } + + @Throws(JniBindingError::class) + public fun zSessionRoutersZid(): List { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zSessionRoutersZid(session_ptr).map { ZZenohId(it) } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zLivelinessDeclareToken(keyExpr: ZKeyExpr): ZLivelinessToken { + return withSortedHandleLocks(this, keyExpr) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + ZLivelinessToken(JNINative.zLivelinessDeclareToken(session_ptr, keyExpr_ptr)) + } finally { + keyExpr.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun livelinessDeclareToken(keyExpr: KeyExpr): ZLivelinessToken { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZLivelinessToken(JNINative.livelinessDeclareToken(session_ptr, keyExpr)) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zLivelinessGet(keyExpr: ZKeyExpr, timeoutMs: Long, callback: ZReplyCallback, onClose: Callback) { + withSortedHandleLocks(this, keyExpr) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zLivelinessGet(session_ptr, keyExpr_ptr, timeoutMs, callback, onClose) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun livelinessGet(keyExpr: KeyExpr, timeoutMs: Long, callback: ReplyCallback, onClose: Callback) { + withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.livelinessGet(session_ptr, keyExpr, timeoutMs, callback, onClose) + } + } + + @Throws(Error::class, JniBindingError::class) + public fun zLivelinessDeclareSubscriber(keyExpr: ZKeyExpr, history: Boolean, callback: ZSampleCallback, onClose: Callback): ZSubscriber { + return withSortedHandleLocks(this, keyExpr) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + val keyExpr_ptr = keyExpr.ptr + if (keyExpr_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + ZSubscriber(JNINative.zLivelinessDeclareSubscriber(session_ptr, keyExpr_ptr, history, callback, onClose)) + } finally { + keyExpr.ptr = 0L + } + } + } + + @Throws(Error::class, JniBindingError::class) + public fun livelinessDeclareSubscriber(keyExpr: KeyExpr, history: Boolean, callback: SampleCallback, onClose: Callback): ZSubscriber { + return withSortedHandleLocks(this) { + val session_ptr = this.ptr + if (session_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + ZSubscriber(JNINative.livelinessDeclareSubscriber(session_ptr, keyExpr, history, callback, onClose)) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + + @Throws(Error::class, JniBindingError::class) + public fun zOpen(config: ZConfig): ZSession { + return withSortedHandleLocks(config) { + val config_ptr = config.ptr + if (config_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + try { + ZSession(JNINative.zOpen(config_ptr)) + } finally { + config.ptr = 0L + } + } + } + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/time/Timestamp.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/time/Timestamp.kt new file mode 100644 index 00000000..d87f27fd --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/time/Timestamp.kt @@ -0,0 +1,16 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.time + +public data class Timestamp( + val ntp64: Long, + val id: ByteArray, +) { + public companion object { + @JvmStatic + public fun fromParts( + ntp64: Long, + id: ByteArray + ): Timestamp = + Timestamp(ntp64, id) + } +} diff --git a/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/time/ZTimestamp.kt b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/time/ZTimestamp.kt new file mode 100644 index 00000000..838ad51d --- /dev/null +++ b/zenoh-flat-jni/generated-kotlin/io/zenoh/jni/time/ZTimestamp.kt @@ -0,0 +1,58 @@ +// Auto-generated by JniGen — do not edit by hand. +package io.zenoh.jni.time + +import io.zenoh.jni.JNINative +import io.zenoh.jni.JniBindingError +import io.zenoh.jni.NativeHandle +import io.zenoh.jni.withSortedHandleLocks + +/** Typed handle for a native Zenoh `ZTimestamp`. */ +public class ZTimestamp(initialPtr: Long) : NativeHandle(initialPtr) { + @Synchronized + override fun close() { + val p = ptr + if (p != 0L) { + ptr = 0L + freePtr(p) + } + } + + @Synchronized + public fun take(): ZTimestamp { + val p = ptr + ptr = 0L + return ZTimestamp(p) + } + + @Throws(JniBindingError::class) + public fun zTimestampNtp64(): Long { + return withSortedHandleLocks(this) { + val t_ptr = this.ptr + if (t_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zTimestampNtp64(t_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zTimestampId(): ByteArray { + return withSortedHandleLocks(this) { + val t_ptr = this.ptr + if (t_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zTimestampId(t_ptr) + } + } + + @Throws(JniBindingError::class) + public fun zTimestampExpand(): Timestamp { + return withSortedHandleLocks(this) { + val t_ptr = this.ptr + if (t_ptr == 0L) throw JniBindingError("Operation on a closed native handle.") + JNINative.zTimestampExpand(t_ptr) + } + } + + public companion object { + @JvmStatic + external fun freePtr(ptr: Long) + } +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt b/zenoh-flat-jni/kotlin/io/zenoh/jni/bytes/JNIBytes.kt similarity index 53% rename from zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt rename to zenoh-flat-jni/kotlin/io/zenoh/jni/bytes/JNIBytes.kt index 799b9cac..0a0be218 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZBytes.kt +++ b/zenoh-flat-jni/kotlin/io/zenoh/jni/bytes/JNIBytes.kt @@ -12,22 +12,18 @@ // ZettaScale Zenoh Team, // -package io.zenoh.jni +@file:JvmName("JNIBytes") + +package io.zenoh.jni.bytes import io.zenoh.ZenohLoad -import io.zenoh.bytes.ZBytes import java.lang.reflect.Type -@PublishedApi -internal object JNIZBytes { - - init { - ZenohLoad - } +// Forces the native library to load before the first JNI call. The standalone +// (de)serialization path has no Session to trigger the load, and the facade +// class runs before either external fn below is invoked. +private val ensureLoaded = ZenohLoad - @JvmStatic - external fun serializeViaJNI(any: Any, type: Type): ZBytes +internal external fun serializeViaJNI(any: Any, type: Type): ByteArray - @JvmStatic - external fun deserializeViaJNI(zBytes: ZBytes, type: Type): Any -} +internal external fun deserializeViaJNI(bytes: ByteArray, type: Type): Any diff --git a/zenoh-flat-jni/src/lib.rs b/zenoh-flat-jni/src/lib.rs new file mode 100644 index 00000000..07c51418 --- /dev/null +++ b/zenoh-flat-jni/src/lib.rs @@ -0,0 +1,22 @@ +// Generated `kotlin_enum` decoders use bare type idents (e.g. `WhatAmI`) +// matching the wrapper fn's `v: ` signature. Bring upstream +// enums into scope so those decoders resolve at the include site. +use zenoh_flat::WhatAmI; +use zenoh_flat::SetIntersectionLevel; +use zenoh_flat::CongestionControl; +use zenoh_flat::Priority; +use zenoh_flat::Reliability; +use zenoh_flat::ReplyKeyExpr; +use zenoh_flat::QueryTarget; +use zenoh_flat::ConsolidationMode; +use zenoh_flat::SampleKind; + +// Generated by build.rs into OUT_DIR. +include!(concat!(env!("OUT_DIR"), "/zenoh_flat_jni.rs")); + +// Hand-written ZBytes serialization JNI. Java-specific (walks reflect.Type, +// builds java.util collections), so it lives here rather than in the +// language-agnostic zenoh-flat. Throws io.zenoh.jni.JniBindingError via the +// generated `throw_JniBindingError`. +#[cfg(feature = "zenoh-ext")] +mod zbytes; diff --git a/zenoh-jni/src/zbytes.rs b/zenoh-flat-jni/src/zbytes.rs similarity index 60% rename from zenoh-jni/src/zbytes.rs rename to zenoh-flat-jni/src/zbytes.rs index 627bb8b0..d0c95636 100644 --- a/zenoh-jni/src/zbytes.rs +++ b/zenoh-flat-jni/src/zbytes.rs @@ -17,15 +17,31 @@ use jni::{ sys::jobject, JNIEnv, }; +use prebindgen::lang::JniBindingError; use zenoh::bytes::ZBytes; use zenoh_ext::{VarInt, ZDeserializeError, ZDeserializer, ZSerializer}; -use crate::{ - errors::ZResult, - throw_exception, - utils::{bytes_to_java_array, decode_byte_array}, - zerror, -}; +use crate::throw_JniBindingError; + +type JResult = core::result::Result; + +/// Helper function to convert a JByteArray into a Vec. +fn decode_byte_array(env: &JNIEnv<'_>, payload: JByteArray) -> JResult> { + let payload_len = env + .get_array_length(&payload) + .map(|length| length as usize) + .map_err(|err| JniBindingError(err.to_string()))?; + let mut buff = vec![0; payload_len]; + env.get_byte_array_region(payload, 0, &mut buff[..]) + .map_err(|err| JniBindingError(err.to_string()))?; + let buff: Vec = unsafe { std::mem::transmute::, Vec>(buff) }; + Ok(buff) +} + +fn bytes_to_java_array<'a>(env: &JNIEnv<'a>, slice: &ZBytes) -> JResult> { + env.byte_array_from_slice(&slice.to_bytes()) + .map_err(|err| JniBindingError(err.to_string())) +} enum JavaType { Boolean, @@ -41,16 +57,16 @@ enum JavaType { Map(Box, Box), } -fn decode_token_type(env: &mut JNIEnv, type_obj: JObject) -> ZResult { +fn decode_token_type(env: &mut JNIEnv, type_obj: JObject) -> JResult { let type_name_jobject = env .call_method(&type_obj, "getTypeName", "()Ljava/lang/String;", &[]) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .l() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let qualified_name: String = env .get_string(&JString::from(type_name_jobject)) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .into(); match qualified_name.as_str() { @@ -66,7 +82,7 @@ fn decode_token_type(env: &mut JNIEnv, type_obj: JObject) -> ZResult { _ => { let type_token_class = env .find_class("com/google/common/reflect/TypeToken") - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let token_type = env .call_static_method( type_token_class, @@ -74,12 +90,12 @@ fn decode_token_type(env: &mut JNIEnv, type_obj: JObject) -> ZResult { "(Ljava/lang/reflect/Type;)Lcom/google/common/reflect/TypeToken;", &[JValue::Object(&type_obj)], ) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .l() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let map_class: JObject = env .find_class("java/util/Map") - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .into(); let is_map_subtype = env .call_method( @@ -88,9 +104,9 @@ fn decode_token_type(env: &mut JNIEnv, type_obj: JObject) -> ZResult { "(Ljava/lang/reflect/Type;)Z", &[JValue::Object(&map_class)], ) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .z() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; if is_map_subtype { let args = env @@ -100,16 +116,16 @@ fn decode_token_type(env: &mut JNIEnv, type_obj: JObject) -> ZResult { "()[Ljava/lang/reflect/Type;", &[], ) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .l() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let jobject_array = JObjectArray::from(args); let arg1 = env .get_object_array_element(&jobject_array, 0) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let arg2 = env .get_object_array_element(&jobject_array, 1) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; return Ok(JavaType::Map( Box::new(decode_token_type(env, arg1)?), @@ -119,7 +135,7 @@ fn decode_token_type(env: &mut JNIEnv, type_obj: JObject) -> ZResult { let list_class: JObject = env .find_class("java/util/List") - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .into(); let is_list_subtype = env .call_method( @@ -128,9 +144,9 @@ fn decode_token_type(env: &mut JNIEnv, type_obj: JObject) -> ZResult { "(Ljava/lang/reflect/Type;)Z", &[JValue::Object(&list_class)], ) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .z() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; if is_list_subtype { let args = env @@ -140,49 +156,44 @@ fn decode_token_type(env: &mut JNIEnv, type_obj: JObject) -> ZResult { "()[Ljava/lang/reflect/Type;", &[], ) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .l() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let jobject_array = JObjectArray::from(args); let arg1 = env .get_object_array_element(&jobject_array, 0) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; return Ok(JavaType::List(Box::new(decode_token_type(env, arg1)?))); } - Err(zerror!("Unsupported type: {}", qualified_name)) + Err(JniBindingError(format!( + "Unsupported type: {}", + qualified_name + ))) } } } #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIZBytes_serializeViaJNI( +pub extern "C" fn Java_io_zenoh_jni_bytes_JNIBytes_serializeViaJNI( mut env: JNIEnv, _class: JClass, any: JObject, token_type: JObject, ) -> jobject { - || -> ZResult { + || -> JResult { let mut serializer = ZSerializer::new(); let jtype = decode_token_type(&mut env, token_type)?; serialize(&mut env, &mut serializer, any, &jtype)?; let zbytes = serializer.finish(); - let byte_array = bytes_to_java_array(&env, &zbytes).map_err(|err| zerror!(err))?; - let zbytes_obj = env - .new_object( - "io/zenoh/bytes/ZBytes", - "([B)V", - &[JValue::Object(&JObject::from(byte_array))], - ) - .map_err(|err| zerror!(err))?; - - Ok(zbytes_obj.as_raw()) + let byte_array = bytes_to_java_array(&env, &zbytes)?; + Ok(byte_array.as_raw()) }() .unwrap_or_else(|err| { - throw_exception!(env, err); + throw_JniBindingError(&mut env, &err); JObject::default().as_raw() }) } @@ -192,97 +203,112 @@ fn serialize( serializer: &mut ZSerializer, any: JObject, jtype: &JavaType, -) -> ZResult<()> { +) -> JResult<()> { match jtype { JavaType::Byte => { let byte_value = env .call_method(any, "byteValue", "()B", &[]) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .b() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; serializer.serialize(byte_value); } JavaType::Short => { let short_value = env .call_method(any, "shortValue", "()S", &[]) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .s() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; serializer.serialize(short_value); } JavaType::Int => { let int_value = env .call_method(any, "intValue", "()I", &[]) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .i() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; serializer.serialize(int_value); } JavaType::Long => { let long_value = env .call_method(any, "longValue", "()J", &[]) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .j() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; serializer.serialize(long_value); } JavaType::Float => { let float_value = env .call_method(any, "floatValue", "()F", &[]) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .f() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; serializer.serialize(float_value); } JavaType::Double => { let double_value = env .call_method(any, "doubleValue", "()D", &[]) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .d() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; serializer.serialize(double_value); } JavaType::Boolean => { let boolean_value = env .call_method(any, "booleanValue", "()Z", &[]) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .z() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; serializer.serialize(boolean_value); } JavaType::String => { let jstring = JString::from(any); - let string_value: String = env.get_string(&jstring).map_err(|err| zerror!(err))?.into(); + let string_value: String = env + .get_string(&jstring) + .map_err(|err| JniBindingError(err.to_string()))? + .into(); serializer.serialize(string_value); } JavaType::ByteArray => { let jbyte_array = JByteArray::from(any); - let bytes = decode_byte_array(env, jbyte_array).map_err(|err| zerror!(err))?; + let bytes = decode_byte_array(env, jbyte_array)?; serializer.serialize(bytes); } JavaType::List(kotlin_type) => { let jlist: JList<'_, '_, '_> = - JList::from_env(env, &any).map_err(|err| zerror!(err))?; - let mut iterator = jlist.iter(env).map_err(|err| zerror!(err))?; - let list_size = jlist.size(env).map_err(|err| zerror!(err))?; - serializer.serialize(zenoh_ext::VarInt(list_size as usize)); - while let Some(value) = iterator.next(env).map_err(|err| zerror!(err))? { + JList::from_env(env, &any).map_err(|err| JniBindingError(err.to_string()))?; + let mut iterator = jlist + .iter(env) + .map_err(|err| JniBindingError(err.to_string()))?; + let list_size = jlist + .size(env) + .map_err(|err| JniBindingError(err.to_string()))?; + serializer.serialize(VarInt(list_size as usize)); + while let Some(value) = iterator + .next(env) + .map_err(|err| JniBindingError(err.to_string()))? + { serialize(env, serializer, value, kotlin_type)?; } } JavaType::Map(key_type, value_type) => { - let jmap = JMap::from_env(env, &any).map_err(|err| zerror!(err))?; + let jmap = JMap::from_env(env, &any).map_err(|err| JniBindingError(err.to_string()))?; let map_size = env .call_method(&jmap, "size", "()I", &[]) - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .i() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; - serializer.serialize(zenoh_ext::VarInt(map_size as usize)); + serializer.serialize(VarInt(map_size as usize)); - let mut iterator = jmap.iter(env).map_err(|err| zerror!(err))?; - while let Some((key, value)) = iterator.next(env).map_err(|err| zerror!(err))? { + let mut iterator = jmap + .iter(env) + .map_err(|err| JniBindingError(err.to_string()))?; + while let Some((key, value)) = iterator + .next(env) + .map_err(|err| JniBindingError(err.to_string()))? + { serialize(env, serializer, key, key_type)?; serialize(env, serializer, value, value_type)?; } @@ -293,31 +319,25 @@ fn serialize( #[no_mangle] #[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIZBytes_deserializeViaJNI( +pub extern "C" fn Java_io_zenoh_jni_bytes_JNIBytes_deserializeViaJNI( mut env: JNIEnv, _class: JClass, - zbytes: JObject, + bytes: JByteArray, jtype: JObject, ) -> jobject { - || -> ZResult { - let payload = env - .get_field(zbytes, "bytes", "[B") - .map_err(|err| zerror!(err))?; - let decoded_bytes: Vec = decode_byte_array( - &env, - JByteArray::from(payload.l().map_err(|err| zerror!(err))?), - )?; + || -> JResult { + let decoded_bytes: Vec = decode_byte_array(&env, bytes)?; let zbytes = ZBytes::from(decoded_bytes); let mut deserializer = ZDeserializer::new(&zbytes); let jtype = decode_token_type(&mut env, jtype)?; let obj = deserialize(&mut env, &mut deserializer, &jtype)?; if !deserializer.done() { - return Err(zerror!(ZDeserializeError)); + return Err(JniBindingError(ZDeserializeError.to_string())); } Ok(obj) }() .unwrap_or_else(|err| { - throw_exception!(env, err); + throw_JniBindingError(&mut env, &err); JObject::default().as_raw() }) } @@ -326,116 +346,119 @@ fn deserialize( env: &mut JNIEnv, deserializer: &mut ZDeserializer, jtype: &JavaType, -) -> ZResult { +) -> JResult { match jtype { JavaType::Byte => { let byte = deserializer .deserialize::() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let byte_obj = env .new_object("java/lang/Byte", "(B)V", &[JValue::Byte(byte)]) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; Ok(byte_obj.as_raw()) } JavaType::Short => { let short = deserializer .deserialize::() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let short_obj = env .new_object("java/lang/Short", "(S)V", &[JValue::Short(short)]) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; Ok(short_obj.as_raw()) } JavaType::Int => { let integer = deserializer .deserialize::() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let integer_obj = env .new_object("java/lang/Integer", "(I)V", &[JValue::Int(integer)]) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; Ok(integer_obj.as_raw()) } JavaType::Long => { let long = deserializer .deserialize::() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let long_obj = env .new_object("java/lang/Long", "(J)V", &[JValue::Long(long)]) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; Ok(long_obj.as_raw()) } JavaType::Float => { let float = deserializer .deserialize::() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let float_obj = env .new_object("java/lang/Float", "(F)V", &[JValue::Float(float)]) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; Ok(float_obj.as_raw()) } JavaType::Double => { let double = deserializer .deserialize::() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let double_obj = env .new_object("java/lang/Double", "(D)V", &[JValue::Double(double)]) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; Ok(double_obj.as_raw()) } JavaType::Boolean => { let boolean_value = deserializer .deserialize::() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let jboolean = if boolean_value { 1u8 } else { 0u8 }; let boolean_obj = env .new_object("java/lang/Boolean", "(Z)V", &[JValue::Bool(jboolean)]) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; Ok(boolean_obj.as_raw()) } JavaType::String => { let deserialized_string = deserializer .deserialize::() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let jstring = env .new_string(&deserialized_string) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; Ok(jstring.into_raw()) } JavaType::ByteArray => { let deserialized_bytes = deserializer .deserialize::>() - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; let jbytes = env .byte_array_from_slice(deserialized_bytes.as_slice()) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; Ok(jbytes.into_raw()) } JavaType::List(kotlin_type) => { let list_size = deserializer .deserialize::>() - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .0; let array_list = env .new_object("java/util/ArrayList", "()V", &[]) - .map_err(|err| zerror!(err))?; - let jlist = JList::from_env(env, &array_list).map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; + let jlist = + JList::from_env(env, &array_list).map_err(|err| JniBindingError(err.to_string()))?; for _ in 0..list_size { let item = deserialize(env, deserializer, kotlin_type)?; let item_obj = unsafe { JObject::from_raw(item) }; - jlist.add(env, &item_obj).map_err(|err| zerror!(err))?; + jlist + .add(env, &item_obj) + .map_err(|err| JniBindingError(err.to_string()))?; } Ok(array_list.as_raw()) } JavaType::Map(key_type, value_type) => { let map_size = deserializer .deserialize::>() - .map_err(|err| zerror!(err))? + .map_err(|err| JniBindingError(err.to_string()))? .0; let map = env .new_object("java/util/HashMap", "()V", &[]) - .map_err(|err| zerror!(err))?; - let jmap = JMap::from_env(env, &map).map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; + let jmap = JMap::from_env(env, &map).map_err(|err| JniBindingError(err.to_string()))?; for _ in 0..map_size { let key = deserialize(env, deserializer, key_type)?; @@ -443,7 +466,7 @@ fn deserialize( let value = deserialize(env, deserializer, value_type)?; let value_obj = unsafe { JObject::from_raw(value) }; jmap.put(env, &key_obj, &value_obj) - .map_err(|err| zerror!(err))?; + .map_err(|err| JniBindingError(err.to_string()))?; } Ok(map.as_raw()) } diff --git a/zenoh-java/build.gradle.kts b/zenoh-java/build.gradle.kts index 123d7499..f475c52c 100644 --- a/zenoh-java/build.gradle.kts +++ b/zenoh-java/build.gradle.kts @@ -31,6 +31,9 @@ val release = project.findProperty("release")?.toString()?.toBoolean() == true val isRemotePublication = project.findProperty("remotePublication")?.toString()?.toBoolean() == true var buildMode = if (release) BuildMode.RELEASE else BuildMode.DEBUG +// Native dylib comes from zenoh-flat-jni. +val zenohFlatJniTargetDir = "../zenoh-flat-jni/target/$buildMode" +val nativeLibraryPath = zenohFlatJniTargetDir if (androidEnabled) { apply(plugin = "com.android.library") @@ -47,8 +50,7 @@ kotlin { kotlinOptions.jvmTarget = "11" } testRuns["test"].executionTask.configure { - val zenohPaths = "../zenoh-jni/target/$buildMode" - jvmArgs("-Djava.library.path=$zenohPaths") + jvmArgs("-Djava.library.path=$nativeLibraryPath") } if (!androidEnabled) { withJava() // Adding java to a kotlin lib targeting android is incompatible @@ -65,6 +67,8 @@ kotlin { @Suppress("Unused") sourceSets { val commonMain by getting { + kotlin.srcDir("../zenoh-flat-jni/generated-kotlin") + kotlin.srcDir("../zenoh-flat-jni/kotlin") dependencies { implementation("commons-net:commons-net:3.9.0") implementation("com.google.guava:guava:33.3.1-jre") @@ -87,12 +91,12 @@ kotlin { // The line below is intended to load the native libraries that are crosscompiled on GitHub actions when publishing a JVM package. resources.srcDir("../jni-libs").include("*/**") } else { - resources.srcDir("../zenoh-jni/target/$buildMode").include(arrayListOf("*.dylib", "*.so", "*.dll")) + resources.srcDir(zenohFlatJniTargetDir).include(arrayListOf("*.dylib", "*.so", "*.dll")) } } val jvmTest by getting { - resources.srcDir("../zenoh-jni/target/$buildMode").include(arrayListOf("*.dylib", "*.so", "*.dll")) + resources.srcDir(zenohFlatJniTargetDir).include(arrayListOf("*.dylib", "*.so", "*.dll")) } } @@ -157,7 +161,7 @@ tasks.withType { doFirst { // The line below is added for the Android Unit tests which are equivalent to the JVM tests. // For them to work we need to specify the path to the native library as a system property and not as a jvmArg. - systemProperty("java.library.path", "../zenoh-jni/target/$buildMode") + systemProperty("java.library.path", nativeLibraryPath) } } @@ -168,20 +172,20 @@ tasks.whenObjectAdded { } tasks.named("compileKotlinJvm") { - dependsOn("buildZenohJni") + dependsOn("buildZenohFlatJni") } -tasks.register("buildZenohJni") { +tasks.register("buildZenohFlatJni") { doLast { if (!isRemotePublication) { // This is intended for local publications. For publications done through GitHub workflows, - // the zenoh-jni build is achieved and loaded differently from the CI - buildZenohJNI(buildMode) + // the zenoh-flat-jni build is achieved and loaded differently from the CI + buildZenohFlatJNI(buildMode) } } } -fun buildZenohJNI(mode: BuildMode = BuildMode.DEBUG) { +fun buildZenohFlatJNI(mode: BuildMode = BuildMode.DEBUG) { val cargoCommand = mutableListOf("cargo", "build") if (mode == BuildMode.RELEASE) { @@ -189,11 +193,11 @@ fun buildZenohJNI(mode: BuildMode = BuildMode.DEBUG) { } val result = project.exec { - commandLine(*(cargoCommand.toTypedArray()), "--manifest-path", "../zenoh-jni/Cargo.toml") + commandLine(*(cargoCommand.toTypedArray()), "--manifest-path", "../zenoh-flat-jni/Cargo.toml") } if (result.exitValue != 0) { - throw GradleException("Failed to build Zenoh-JNI.") + throw GradleException("Failed to build Zenoh-Flat-JNI.") } Thread.sleep(1000) @@ -253,10 +257,10 @@ fun Project.configureAndroid() { fun Project.configureCargo() { extensions.configure("cargo") { pythonCommand = "python3" - module = "../zenoh-jni" - libname = "zenoh-jni" - targetIncludes = arrayOf("libzenoh_jni.so") - targetDirectory = "../zenoh-jni/target/" + module = "../zenoh-flat-jni" + libname = "zenoh-flat-jni" + targetIncludes = arrayOf("libzenoh_flat_jni.so") + targetDirectory = "../zenoh-flat-jni/target/" profile = "release" targets = arrayListOf( "arm", diff --git a/zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt b/zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt index 74d42e51..3368ab93 100644 --- a/zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt +++ b/zenoh-java/src/androidMain/kotlin/io.zenoh/Zenoh.kt @@ -19,7 +19,7 @@ package io.zenoh * log level configuration. */ internal actual object ZenohLoad { - private const val ZENOH_LIB_NAME = "zenoh_jni" + private const val ZENOH_LIB_NAME = "zenoh_flat_jni" init { System.loadLibrary(ZENOH_LIB_NAME) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt index 91bc0e01..21de74e9 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt @@ -14,8 +14,10 @@ package io.zenoh +import io.zenoh.ZenohLoad import io.zenoh.exceptions.ZError -import io.zenoh.jni.JNIConfig +import io.zenoh.exceptions.wrapJNIExceptionAsZError +import io.zenoh.jni.config.ZConfig import java.io.File import java.nio.file.Path @@ -35,18 +37,22 @@ import java.nio.file.Path * Visit the [default configuration](https://github.com/eclipse-zenoh/zenoh/blob/main/DEFAULT_CONFIG.json5) for more * information on the Zenoh config parameters. */ -class Config internal constructor(internal val jniConfig: JNIConfig) { +class Config internal constructor(internal val zConfig: ZConfig) { companion object { + init { + ZenohLoad + } + private const val CONFIG_ENV = "ZENOH_CONFIG" /** * Returns the default config. */ @JvmStatic - fun loadDefault(): Config { - return JNIConfig.loadDefaultConfig() + fun loadDefault(): Config = wrapJNIExceptionAsZError { + Config(ZConfig.zConfigDefault()) } /** @@ -58,9 +64,7 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { */ @JvmStatic @Throws(ZError::class) - fun fromFile(file: File): Config { - return JNIConfig.loadConfigFile(file) - } + fun fromFile(file: File): Config = fromFile(file.toPath()) /** * Loads the configuration from the [Path] specified. @@ -71,8 +75,8 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { */ @JvmStatic @Throws(ZError::class) - fun fromFile(path: Path): Config { - return JNIConfig.loadConfigFile(path) + fun fromFile(path: Path): Config = wrapJNIExceptionAsZError { + Config(ZConfig.zConfigFromFile(path.toString())) } /** @@ -86,8 +90,8 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { */ @JvmStatic @Throws(ZError::class) - fun fromJson(config: String): Config { - return JNIConfig.loadJsonConfig(config) + fun fromJson(config: String): Config = wrapJNIExceptionAsZError { + Config(ZConfig.zConfigFromJson(config)) } /** @@ -101,8 +105,8 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { */ @JvmStatic @Throws(ZError::class) - fun fromJson5(config: String): Config { - return JNIConfig.loadJson5Config(config) + fun fromJson5(config: String): Config = wrapJNIExceptionAsZError { + Config(ZConfig.zConfigFromJson5(config)) } /** @@ -116,8 +120,8 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { */ @JvmStatic @Throws(ZError::class) - fun fromYaml(config: String): Config { - return JNIConfig.loadYamlConfig(config) + fun fromYaml(config: String): Config = wrapJNIExceptionAsZError { + Config(ZConfig.zConfigFromYaml(config)) } /** @@ -141,19 +145,15 @@ class Config internal constructor(internal val jniConfig: JNIConfig) { * The json value associated to the [key]. */ @Throws(ZError::class) - fun getJson(key: String): String { - return jniConfig.getJson(key) + fun getJson(key: String): String = wrapJNIExceptionAsZError { + zConfig.zConfigGetJson(key) } /** * Inserts a json5 value associated to the [key] into the Config. */ @Throws(ZError::class) - fun insertJson5(key: String, value: String) { - jniConfig.insertJson5(key, value) - } - - protected fun finalize() { - jniConfig.close() + fun insertJson5(key: String, value: String) = wrapJNIExceptionAsZError { + zConfig.zConfigInsertJson5(key, value) } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/FlatCallbacks.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/FlatCallbacks.kt new file mode 100644 index 00000000..ba762353 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/FlatCallbacks.kt @@ -0,0 +1,88 @@ +// +// Copyright (c) 2023 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh + +import io.zenoh.config.WhatAmI +import io.zenoh.config.ZenohId +import io.zenoh.query.Query +import io.zenoh.query.Reply +import io.zenoh.sample.Sample +import io.zenoh.scouting.Hello + +/** + * Adapters from the *flattened* JNI callback fun-interfaces (the native side + * delivers each `Sample`/`Query`/`Reply`/`Hello` as its leaf wires in a single + * `run(...)` crossing — no intermediate `jni.` object, no round-trip) + * to a plain `(SdkType) -> Unit`. The leaf wires are reassembled into the + * SDK object graph in JVM bytecode here, so call sites stay one-liners. The + * long parameter lists (matching the generated `run`/`fromParts` order) live + * here only. + */ + +internal fun sampleCallbackOf(f: (Sample) -> Unit): io.zenoh.jni.callbacks.SampleCallback = + io.zenoh.jni.callbacks.SampleCallback { + keyExprString, keyExprNative, payload, encodingId, encodingSchema, kind, + timestampPresent, timestampNtp64, timestampId, express, priority, congestionControl, + attachment -> + f( + Sample.fromFlat( + keyExprString, keyExprNative, payload, encodingId, encodingSchema, kind, + timestampPresent, timestampNtp64, timestampId, express, priority, + congestionControl, attachment + ) + ) + } + +internal fun queryCallbackOf(f: (Query) -> Unit): io.zenoh.jni.callbacks.QueryCallback = + io.zenoh.jni.callbacks.QueryCallback { + keyExprString, keyExprNative, parameters, payload, encodingPresent, encodingId, + encodingSchema, attachment, acceptsReplies, query -> + f( + Query.fromFlat( + keyExprString, keyExprNative, parameters, payload, encodingPresent, encodingId, + encodingSchema, attachment, acceptsReplies, query + ) + ) + } + +internal fun replyCallbackOf(f: (Reply) -> Unit): io.zenoh.jni.callbacks.ReplyCallback = + io.zenoh.jni.callbacks.ReplyCallback { + replierZid, replierEid, samplePresent, sampleKeyExprString, sampleKeyExprNative, + samplePayload, sampleEncodingId, sampleEncodingSchema, sampleKind, sampleTimestampPresent, + sampleTimestampNtp64, sampleTimestampId, sampleExpress, samplePriority, + sampleCongestionControl, sampleAttachment, errorPayload, errorEncodingPresent, + errorEncodingId, errorEncodingSchema -> + f( + Reply.fromFlat( + replierZid, replierEid, samplePresent, sampleKeyExprString, sampleKeyExprNative, + samplePayload, sampleEncodingId, sampleEncodingSchema, sampleKind, + sampleTimestampPresent, sampleTimestampNtp64, sampleTimestampId, sampleExpress, + samplePriority, sampleCongestionControl, sampleAttachment, errorPayload, + errorEncodingPresent, errorEncodingId, errorEncodingSchema + ) + ) + } + +internal fun helloCallbackOf(f: (Hello) -> Unit): io.zenoh.jni.callbacks.HelloCallback = + io.zenoh.jni.callbacks.HelloCallback { whatami, zid, locators -> + // Build io.zenoh.Hello directly from the leaf wires — no jni.Hello object. + f( + Hello( + WhatAmI.fromJni(io.zenoh.jni.config.WhatAmI.fromInt(whatami)), + ZenohId(io.zenoh.jni.config.ZenohId(zid)), + locators + ) + ) + } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt index eba6681c..a6992c85 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Logger.kt @@ -15,6 +15,8 @@ package io.zenoh import io.zenoh.exceptions.ZError +import io.zenoh.exceptions.wrapJNIExceptionAsZError +import io.zenoh.jni.logger.initAndroidLogs /** Logger class to redirect the Rust logs from Zenoh to the kotlin environment. */ internal class Logger { @@ -23,11 +25,6 @@ internal class Logger { internal const val LOG_ENV: String = "RUST_LOG" - @Throws(ZError::class) - fun start(filter: String) { - startLogsViaJNI(filter) - } - /** * Redirects the rust logs either to logcat for Android systems or to the standard output (for non-android * systems). @@ -35,6 +32,8 @@ internal class Logger { * See https://docs.rs/env_logger/latest/env_logger/index.html for accepted filter format. */ @Throws(ZError::class) - private external fun startLogsViaJNI(filter: String) + fun start(filter: String) { + wrapJNIExceptionAsZError { initAndroidLogs(filter) } + } } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index d3b125f9..ec5de3b7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -15,17 +15,21 @@ package io.zenoh import io.zenoh.annotations.Unstable +import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes +import io.zenoh.bytes.into import io.zenoh.config.ZenohId import io.zenoh.exceptions.ZError +import io.zenoh.exceptions.wrapJNIExceptionAsZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback import io.zenoh.handlers.Handler -import io.zenoh.jni.JNISession +import io.zenoh.jni.session.ZSession import io.zenoh.keyexpr.KeyExpr import io.zenoh.liveliness.Liveliness import io.zenoh.pubsub.* +import io.zenoh.qos.QoS import io.zenoh.query.* import io.zenoh.query.Query import io.zenoh.query.Queryable @@ -53,7 +57,7 @@ import java.util.concurrent.LinkedBlockingDeque */ class Session private constructor(private val config: Config) : AutoCloseable { - internal var jniSession: JNISession? = null + internal var zSession: ZSession? = null // Subscribers and Queryables that keep running despite losing references to them. private var strongDeclarations = mutableListOf() @@ -98,8 +102,8 @@ class Session private constructor(private val config: Config) : AutoCloseable { true } - jniSession?.close() - jniSession = null + zSession?.close() + zSession = null } protected fun finalize() { @@ -382,11 +386,12 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ @Throws(ZError::class) fun declareKeyExpr(keyExpr: String): KeyExpr { - return jniSession?.run { - val keyexpr = declareKeyExpr(keyExpr) - strongDeclarations.add(keyexpr) - keyexpr - } ?: throw sessionClosedException + val zSession = zSession ?: throw sessionClosedException + val keyexpr = wrapJNIExceptionAsZError { + KeyExpr(io.zenoh.jni.keyexpr.KeyExpr(keyExpr, zSession.zSessionDeclareKeyexpr(keyExpr))) + } + strongDeclarations.add(keyexpr) + return keyexpr } /** @@ -400,9 +405,14 @@ class Session private constructor(private val config: Config) : AutoCloseable { */ @Throws(ZError::class) fun undeclare(keyExpr: KeyExpr) { - return jniSession?.run { - undeclareKeyExpr(keyExpr) - } ?: throw (sessionClosedException) + val zSession = zSession ?: throw sessionClosedException + val handle = keyExpr.flat.keyExprNative + if (handle == null || handle.isClosed()) { + throw ZError("Attempting to undeclare a non declared key expression.") + } + wrapJNIExceptionAsZError { + zSession.zSessionUndeclareKeyexpr(handle) + } } /** @@ -556,7 +566,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { /** Returns if session is open or has been closed. */ fun isClosed(): Boolean { - return jniSession == null + return zSession == null } /** @@ -575,66 +585,126 @@ class Session private constructor(private val config: Config) : AutoCloseable { @Throws(ZError::class) internal fun resolvePublisher(keyExpr: KeyExpr, options: PublisherOptions): Publisher { - return jniSession?.run { - val publisher = declarePublisher(keyExpr, options) - weakDeclarations.add(WeakReference(publisher)) - publisher - } ?: throw (sessionClosedException) + val zSession = zSession ?: throw sessionClosedException + val publisher = wrapJNIExceptionAsZError { + val zPublisher = zSession.sessionDeclarePublisher( + keyExpr.flat, + options.congestionControl.jni, + options.priority.jni, + options.express, + options.reliability.jni + ) + Publisher( + keyExpr, + options.congestionControl, + options.priority, + options.encoding, + zPublisher, + ) + } + weakDeclarations.add(WeakReference(publisher)) + return publisher } @Throws(ZError::class) internal fun resolveSubscriberWithHandler( keyExpr: KeyExpr, handler: Handler ): HandlerSubscriber { - return jniSession?.run { - val subscriber = declareSubscriberWithHandler(keyExpr, handler) - strongDeclarations.add(subscriber) - subscriber - } ?: throw (sessionClosedException) + val zSession = zSession ?: throw sessionClosedException + val subscriber = wrapJNIExceptionAsZError { + val zSubscriber = zSession.sessionDeclareSubscriber( + keyExpr.flat, + sampleCallbackOf { handler.handle(it) }, + io.zenoh.jni.callbacks.Callback { handler.onClose() } + ) + HandlerSubscriber(keyExpr, zSubscriber, handler.receiver()) + } + strongDeclarations.add(subscriber) + return subscriber } @Throws(ZError::class) internal fun resolveSubscriberWithCallback( keyExpr: KeyExpr, callback: Callback ): CallbackSubscriber { - return jniSession?.run { - val subscriber = declareSubscriberWithCallback(keyExpr, callback) - strongDeclarations.add(subscriber) - subscriber - } ?: throw (sessionClosedException) + val zSession = zSession ?: throw sessionClosedException + val subscriber = wrapJNIExceptionAsZError { + val zSubscriber = zSession.sessionDeclareSubscriber( + keyExpr.flat, + sampleCallbackOf { callback.run(it) }, + io.zenoh.jni.callbacks.Callback { } + ) + CallbackSubscriber(keyExpr, zSubscriber) + } + strongDeclarations.add(subscriber) + return subscriber } @Throws(ZError::class) internal fun resolveQueryableWithHandler( keyExpr: KeyExpr, handler: Handler, options: QueryableOptions ): HandlerQueryable { - return jniSession?.run { - val queryable = declareQueryableWithHandler(keyExpr, handler, options) - strongDeclarations.add(queryable) - queryable - } ?: throw (sessionClosedException) + val zSession = zSession ?: throw sessionClosedException + val queryable = wrapJNIExceptionAsZError { + val zQueryable = zSession.sessionDeclareQueryable( + keyExpr.flat, + options.complete, + queryCallbackOf { handler.handle(it) }, + io.zenoh.jni.callbacks.Callback { handler.onClose() } + ) + HandlerQueryable(keyExpr, zQueryable, handler.receiver()) + } + strongDeclarations.add(queryable) + return queryable } @Throws(ZError::class) internal fun resolveQueryableWithCallback( keyExpr: KeyExpr, callback: Callback, options: QueryableOptions ): CallbackQueryable { - return jniSession?.run { - val queryable = declareQueryableWithCallback(keyExpr, callback, options) - strongDeclarations.add(queryable) - queryable - } ?: throw (sessionClosedException) + val zSession = zSession ?: throw sessionClosedException + val queryable = wrapJNIExceptionAsZError { + val zQueryable = zSession.sessionDeclareQueryable( + keyExpr.flat, + options.complete, + queryCallbackOf { callback.run(it) }, + io.zenoh.jni.callbacks.Callback { } + ) + CallbackQueryable(keyExpr, zQueryable) + } + strongDeclarations.add(queryable) + return queryable } + @OptIn(Unstable::class) private fun resolveQuerier( keyExpr: KeyExpr, options: QuerierOptions ): Querier { - return jniSession?.run { - val querier = declareQuerier(keyExpr, options) - weakDeclarations.add(WeakReference(querier)) - querier - } ?: throw sessionClosedException + val zSession = zSession ?: throw sessionClosedException + val querier = wrapJNIExceptionAsZError { + val zQuerier = zSession.sessionDeclareQuerier( + keyExpr.flat, + options.target.toFlat(), + options.consolidationMode.toFlat(), + options.congestionControl.jni, + options.priority.jni, + options.express, + options.timeout.toMillis(), + options.acceptReplies.toFlat() + ) + Querier( + keyExpr, + QoS( + congestionControl = options.congestionControl, + priority = options.priority, + express = options.express + ), + zQuerier + ) + } + weakDeclarations.add(WeakReference(querier)) + return querier } @Throws(ZError::class) @@ -643,11 +713,27 @@ class Session private constructor(private val config: Config) : AutoCloseable { handler: Handler, options: GetOptions ): R { - return jniSession?.performGetWithHandler( - selector, - handler, - options - ) ?: throw sessionClosedException + val zSession = zSession ?: throw sessionClosedException + return wrapJNIExceptionAsZError { + val sel = selector.into() + zSession.sessionGet( + sel.keyExpr.flat, + sel.parameters?.toString(), + options.timeout.toMillis(), + options.target.toFlat(), + options.consolidation.toFlat(), + options.acceptReplies.toFlat(), + options.qos.congestionControl.jni, + options.qos.priority.jni, + options.qos.express, + options.payload?.into()?.inner, + (options.encoding ?: Encoding.defaultEncoding()).toFlat(), + options.attachment?.into()?.inner, + replyCallbackOf { handler.handle(it) }, + io.zenoh.jni.callbacks.Callback { handler.onClose() } + ) + handler.receiver() + } } @Throws(ZError::class) @@ -656,42 +742,84 @@ class Session private constructor(private val config: Config) : AutoCloseable { callback: Callback, options: GetOptions ) { - return jniSession?.performGetWithCallback( - selector, - callback, - options - ) ?: throw sessionClosedException + val zSession = zSession ?: throw sessionClosedException + wrapJNIExceptionAsZError { + val sel = selector.into() + zSession.sessionGet( + sel.keyExpr.flat, + sel.parameters?.toString(), + options.timeout.toMillis(), + options.target.toFlat(), + options.consolidation.toFlat(), + options.acceptReplies.toFlat(), + options.qos.congestionControl.jni, + options.qos.priority.jni, + options.qos.express, + options.payload?.into()?.inner, + (options.encoding ?: Encoding.defaultEncoding()).toFlat(), + options.attachment?.into()?.inner, + replyCallbackOf { callback.run(it) }, + io.zenoh.jni.callbacks.Callback { } + ) + } } @Throws(ZError::class) internal fun resolvePut(keyExpr: KeyExpr, payload: IntoZBytes, putOptions: PutOptions) { - jniSession?.run { performPut(keyExpr, payload, putOptions) } + val zSession = zSession ?: return + wrapJNIExceptionAsZError { + val encoding = putOptions.encoding ?: Encoding.defaultEncoding() + zSession.sessionPut( + keyExpr.flat, + payload.into().inner, + encoding.toFlat(), + putOptions.congestionControl.jni, + putOptions.priority.jni, + putOptions.express, + putOptions.attachment?.into()?.inner, + putOptions.reliability.jni + ) + } } @Throws(ZError::class) internal fun resolveDelete(keyExpr: KeyExpr, deleteOptions: DeleteOptions) { - jniSession?.run { performDelete(keyExpr, deleteOptions) } + val zSession = zSession ?: return + wrapJNIExceptionAsZError { + zSession.sessionDelete( + keyExpr.flat, + deleteOptions.congestionControl.jni, + deleteOptions.priority.jni, + deleteOptions.express, + deleteOptions.attachment?.into()?.inner, + deleteOptions.reliability.jni + ) + } } @Throws(ZError::class) internal fun zid(): ZenohId { - return jniSession?.zid() ?: throw sessionClosedException + val zSession = zSession ?: throw sessionClosedException + return wrapJNIExceptionAsZError { ZenohId(zSession.sessionZid()) } } @Throws(ZError::class) internal fun getPeersId(): List { - return jniSession?.peersZid() ?: throw sessionClosedException + val zSession = zSession ?: throw sessionClosedException + return wrapJNIExceptionAsZError { zSession.sessionPeersZid().map { ZenohId(it) } } } @Throws(ZError::class) internal fun getRoutersId(): List { - return jniSession?.routersZid() ?: throw sessionClosedException + val zSession = zSession ?: throw sessionClosedException + return wrapJNIExceptionAsZError { zSession.sessionRoutersZid().map { ZenohId(it) } } } - /** Launches the session through the jni session, returning the [Session] on success. */ + /** Launches the session, returning the [Session] on success. */ @Throws(ZError::class) private fun launch(): Session { - this.jniSession = JNISession.open(config) + ZenohLoad + this.zSession = wrapJNIExceptionAsZError { ZSession.zOpen(config.zConfig) } return this } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt index 7a5931f8..65506eb8 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Zenoh.kt @@ -19,8 +19,11 @@ import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback import io.zenoh.handlers.Handler -import io.zenoh.jni.JNIScout -import io.zenoh.scouting.* +import io.zenoh.scouting.CallbackScout +import io.zenoh.scouting.HandlerScout +import io.zenoh.scouting.Hello +import io.zenoh.scouting.Scout +import io.zenoh.scouting.ScoutOptions import java.util.* import java.util.concurrent.BlockingQueue import java.util.concurrent.LinkedBlockingDeque @@ -53,7 +56,7 @@ object Zenoh { @Throws(ZError::class) fun scout(scoutOptions: ScoutOptions = ScoutOptions()): HandlerScout>> { val handler = BlockingQueueHandler(LinkedBlockingDeque>()) - return JNIScout.scoutWithHandler( + return Scout.scoutWithHandler( scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() }, receiver = handler.receiver(), config = scoutOptions.config ) @@ -74,7 +77,7 @@ object Zenoh { @JvmStatic @Throws(ZError::class) fun scout(handler: Handler, scoutOptions: ScoutOptions = ScoutOptions()): HandlerScout { - return JNIScout.scoutWithHandler( + return Scout.scoutWithHandler( scoutOptions.whatAmI, handler::handle, fun() { handler.onClose() }, receiver = handler.receiver(), config = scoutOptions.config ) @@ -94,7 +97,7 @@ object Zenoh { @JvmStatic @Throws(ZError::class) fun scout(callback: Callback, scoutOptions: ScoutOptions = ScoutOptions()): CallbackScout { - return JNIScout.scoutWithCallback( + return Scout.scoutWithCallback( scoutOptions.whatAmI, callback, config = scoutOptions.config ) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt index a4f77815..47c596c0 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/Encoding.kt @@ -14,6 +14,8 @@ package io.zenoh.bytes +import io.zenoh.jni.bytes.Encoding as JniEncoding + /** * Default encoding values used by Zenoh. * @@ -26,477 +28,221 @@ package io.zenoh.bytes * This is particularly useful in helping Zenoh to perform additional network optimizations. */ class Encoding private constructor( - internal val id: Int, - internal val schema: String? = null, - private val description: String? = null + private val eagerInner: JniEncoding?, + private val leafId: Int, + private val leafSchema: String?, ) { - internal constructor(id: Int, schema: String? = null) : this(id, schema, null) + + /** Eager path: an already-built [JniEncoding] (the predefined constants). */ + internal constructor(inner: JniEncoding) : this(inner, 0, null) + + /** + * Lazy leaf path (hot inbound callback): keep only `id` + `schema`; the + * [JniEncoding] is built on first `.inner`/`.toFlat()` access (native ops / + * outbound only). An inbound-only encoding never allocates a `JniEncoding`. + */ + internal constructor(id: Int, schema: String? = null) : this(null, id, schema) + + /** The native-facing flat form; builds the [JniEncoding] lazily for the leaf path. */ + internal val inner: JniEncoding + get() = eagerInner ?: lazyInner + private val lazyInner: JniEncoding by lazy { JniEncoding(leafId, leafSchema) } + + internal val id: Int get() = eagerInner?.id ?: leafId + internal val schema: String? get() = eagerInner?.schema ?: leafSchema companion object { - /** - * Just some bytes. - * - * Constant alias for string: `"zenoh/bytes"`. - * - * Usually used for types: `ByteArray`, `List`. - */ - @JvmField - val ZENOH_BYTES = Encoding(0, description = "zenoh/bytes") + /** Just some bytes. Constant alias for string: `"zenoh/bytes"`. */ + @JvmField val ZENOH_BYTES = Encoding(JniEncoding.encodingZenohBytes()) - /** - * A UTF-8 string. - * - * Constant alias for string: `"zenoh/string"`. - * - * Usually used for type: `String`. - */ - @JvmField - val ZENOH_STRING = Encoding(1, description = "zenoh/string") + /** A UTF-8 string. Constant alias for string: `"zenoh/string"`. */ + @JvmField val ZENOH_STRING = Encoding(JniEncoding.encodingZenohString()) - /** - * Zenoh serialized data. - * - * Constant alias for string: `"zenoh/serialized"`. - */ - @JvmField - val ZENOH_SERIALIZED = Encoding(2, description = "zenoh/serialized") + /** Zenoh serialized data. Constant alias for string: `"zenoh/serialized"`. */ + @JvmField val ZENOH_SERIALIZED = Encoding(JniEncoding.encodingZenohSerialized()) - /** - * An application-specific stream of bytes. - * - * Constant alias for string: `"application/octet-stream"`. - */ - @JvmField - val APPLICATION_OCTET_STREAM = Encoding(3, description = "application/octet-stream") + /** An application-specific stream of bytes. Constant alias for string: `"application/octet-stream"`. */ + @JvmField val APPLICATION_OCTET_STREAM = Encoding(JniEncoding.encodingApplicationOctetStream()) - /** - * A textual file. - * - * Constant alias for string: `"text/plain"`. - */ - @JvmField - val TEXT_PLAIN = Encoding(4, description = "text/plain") + /** A textual file. Constant alias for string: `"text/plain"`. */ + @JvmField val TEXT_PLAIN = Encoding(JniEncoding.encodingTextPlain()) - /** - * JSON data intended to be consumed by an application. - * - * Constant alias for string: `"application/json"`. - */ - @JvmField - val APPLICATION_JSON = Encoding(5, description = "application/json") + /** JSON data intended to be consumed by an application. Constant alias for string: `"application/json"`. */ + @JvmField val APPLICATION_JSON = Encoding(JniEncoding.encodingApplicationJson()) - /** - * JSON data intended to be human readable. - * - * Constant alias for string: `"text/json"`. - */ - @JvmField - val TEXT_JSON = Encoding(6, description = "text/json") + /** JSON data intended to be human readable. Constant alias for string: `"text/json"`. */ + @JvmField val TEXT_JSON = Encoding(JniEncoding.encodingTextJson()) - /** - * A Common Data Representation (CDR)-encoded data. - * - * Constant alias for string: `"application/cdr"`. - */ - @JvmField - val APPLICATION_CDR = Encoding(7, description = "application/cdr") + /** A Common Data Representation (CDR)-encoded data. Constant alias for string: `"application/cdr"`. */ + @JvmField val APPLICATION_CDR = Encoding(JniEncoding.encodingApplicationCdr()) - /** - * A Concise Binary Object Representation (CBOR)-encoded data. - * - * Constant alias for string: `"application/cbor"`. - */ - @JvmField - val APPLICATION_CBOR = Encoding(8, description = "application/cbor") + /** A Concise Binary Object Representation (CBOR)-encoded data. Constant alias for string: `"application/cbor"`. */ + @JvmField val APPLICATION_CBOR = Encoding(JniEncoding.encodingApplicationCbor()) - /** - * YAML data intended to be consumed by an application. - * - * Constant alias for string: `"application/yaml"`. - */ - @JvmField - val APPLICATION_YAML = Encoding(9, description = "application/yaml") + /** YAML data intended to be consumed by an application. Constant alias for string: `"application/yaml"`. */ + @JvmField val APPLICATION_YAML = Encoding(JniEncoding.encodingApplicationYaml()) - /** - * YAML data intended to be human readable. - * - * Constant alias for string: `"text/yaml"`. - */ - @JvmField - val TEXT_YAML = Encoding(10, description = "text/yaml") + /** YAML data intended to be human readable. Constant alias for string: `"text/yaml"`. */ + @JvmField val TEXT_YAML = Encoding(JniEncoding.encodingTextYaml()) - /** - * JSON5 encoded data that are human readable. - * - * Constant alias for string: `"text/json5"`. - */ - @JvmField - val TEXT_JSON5 = Encoding(11, description = "text/json5") + /** JSON5 encoded data that are human readable. Constant alias for string: `"text/json5"`. */ + @JvmField val TEXT_JSON5 = Encoding(JniEncoding.encodingTextJson5()) - /** - * A Python object serialized using [pickle](https://docs.python.org/3/library/pickle.html). - * - * Constant alias for string: `"application/python-serialized-object"`. - */ - @JvmField - val APPLICATION_PYTHON_SERIALIZED_OBJECT = - Encoding(12, description = "application/python-serialized-object") + /** A Python object serialized using [pickle](https://docs.python.org/3/library/pickle.html). Constant alias for string: `"application/python-serialized-object"`. */ + @JvmField val APPLICATION_PYTHON_SERIALIZED_OBJECT = Encoding(JniEncoding.encodingApplicationPythonSerializedObject()) - /** - * An application-specific protobuf-encoded data. - * - * Constant alias for string: `"application/protobuf"`. - */ - @JvmField - val APPLICATION_PROTOBUF = Encoding(13, description = "application/protobuf") + /** An application-specific protobuf-encoded data. Constant alias for string: `"application/protobuf"`. */ + @JvmField val APPLICATION_PROTOBUF = Encoding(JniEncoding.encodingApplicationProtobuf()) - /** - * A Java serialized object. - * - * Constant alias for string: `"application/java-serialized-object"`. - */ - @JvmField - val APPLICATION_JAVA_SERIALIZED_OBJECT = - Encoding(14, description = "application/java-serialized-object") + /** A Java serialized object. Constant alias for string: `"application/java-serialized-object"`. */ + @JvmField val APPLICATION_JAVA_SERIALIZED_OBJECT = Encoding(JniEncoding.encodingApplicationJavaSerializedObject()) - /** - * OpenMetrics data, commonly used by [Prometheus](https://prometheus.io/). - * - * Constant alias for string: `"application/openmetrics-text"`. - */ - @JvmField - val APPLICATION_OPENMETRICS_TEXT = - Encoding(15, description = "application/openmetrics-text") + /** OpenMetrics data, commonly used by [Prometheus](https://prometheus.io/). Constant alias for string: `"application/openmetrics-text"`. */ + @JvmField val APPLICATION_OPENMETRICS_TEXT = Encoding(JniEncoding.encodingApplicationOpenmetricsText()) - /** - * A Portable Network Graphics (PNG) image. - * - * Constant alias for string: `"image/png"`. - */ - @JvmField - val IMAGE_PNG = Encoding(16, description = "image/png") + /** A Portable Network Graphics (PNG) image. Constant alias for string: `"image/png"`. */ + @JvmField val IMAGE_PNG = Encoding(JniEncoding.encodingImagePng()) - /** - * A Joint Photographic Experts Group (JPEG) image. - * - * Constant alias for string: `"image/jpeg"`. - */ - @JvmField - val IMAGE_JPEG = Encoding(17, description = "image/jpeg") + /** A Joint Photographic Experts Group (JPEG) image. Constant alias for string: `"image/jpeg"`. */ + @JvmField val IMAGE_JPEG = Encoding(JniEncoding.encodingImageJpeg()) - /** - * A Graphics Interchange Format (GIF) image. - * - * Constant alias for string: `"image/gif"`. - */ - @JvmField - val IMAGE_GIF = Encoding(18, description = "image/gif") + /** A Graphics Interchange Format (GIF) image. Constant alias for string: `"image/gif"`. */ + @JvmField val IMAGE_GIF = Encoding(JniEncoding.encodingImageGif()) - /** - * A BitMap (BMP) image. - * - * Constant alias for string: `"image/bmp"`. - */ - @JvmField - val IMAGE_BMP = Encoding(19, description = "image/bmp") + /** A BitMap (BMP) image. Constant alias for string: `"image/bmp"`. */ + @JvmField val IMAGE_BMP = Encoding(JniEncoding.encodingImageBmp()) - /** - * A WebP image. - * - * Constant alias for string: `"image/webp"`. - */ - @JvmField - val IMAGE_WEBP = Encoding(20, description = "image/webp") + /** A WebP image. Constant alias for string: `"image/webp"`. */ + @JvmField val IMAGE_WEBP = Encoding(JniEncoding.encodingImageWebp()) - /** - * An XML file intended to be consumed by an application. - * - * Constant alias for string: `"application/xml"`. - */ - @JvmField - val APPLICATION_XML = Encoding(21, description = "application/xml") + /** An XML file intended to be consumed by an application. Constant alias for string: `"application/xml"`. */ + @JvmField val APPLICATION_XML = Encoding(JniEncoding.encodingApplicationXml()) - /** - * A list of tuples, each consisting of a name and a value. - * - * Constant alias for string: `"application/x-www-form-urlencoded"`. - */ - @JvmField - val APPLICATION_X_WWW_FORM_URLENCODED = - Encoding(22, description = "application/x-www-form-urlencoded") + /** A list of tuples, each consisting of a name and a value. Constant alias for string: `"application/x-www-form-urlencoded"`. */ + @JvmField val APPLICATION_X_WWW_FORM_URLENCODED = Encoding(JniEncoding.encodingApplicationXWwwFormUrlencoded()) - /** - * An HTML file. - * - * Constant alias for string: `"text/html"`. - */ - @JvmField - val TEXT_HTML = Encoding(23, description = "text/html") + /** An HTML file. Constant alias for string: `"text/html"`. */ + @JvmField val TEXT_HTML = Encoding(JniEncoding.encodingTextHtml()) - /** - * An XML file that is human readable. - * - * Constant alias for string: `"text/xml"`. - */ - @JvmField - val TEXT_XML = Encoding(24, description = "text/xml") + /** An XML file that is human readable. Constant alias for string: `"text/xml"`. */ + @JvmField val TEXT_XML = Encoding(JniEncoding.encodingTextXml()) - /** - * A CSS file. - * - * Constant alias for string: `"text/css"`. - */ - @JvmField - val TEXT_CSS = Encoding(25, description = "text/css") + /** A CSS file. Constant alias for string: `"text/css"`. */ + @JvmField val TEXT_CSS = Encoding(JniEncoding.encodingTextCss()) - /** - * A JavaScript file. - * - * Constant alias for string: `"text/javascript"`. - */ - @JvmField - val TEXT_JAVASCRIPT = Encoding(26, description = "text/javascript") + /** A JavaScript file. Constant alias for string: `"text/javascript"`. */ + @JvmField val TEXT_JAVASCRIPT = Encoding(JniEncoding.encodingTextJavascript()) - /** - * A Markdown file. - * - * Constant alias for string: `"text/markdown"`. - */ - @JvmField - val TEXT_MARKDOWN = Encoding(27, description = "text/markdown") + /** A Markdown file. Constant alias for string: `"text/markdown"`. */ + @JvmField val TEXT_MARKDOWN = Encoding(JniEncoding.encodingTextMarkdown()) - /** - * A CSV file. - * - * Constant alias for string: `"text/csv"`. - */ - @JvmField - val TEXT_CSV = Encoding(28, description = "text/csv") + /** A CSV file. Constant alias for string: `"text/csv"`. */ + @JvmField val TEXT_CSV = Encoding(JniEncoding.encodingTextCsv()) - /** - * An application-specific SQL query. - * - * Constant alias for string: `"application/sql"`. - */ - @JvmField - val APPLICATION_SQL = Encoding(29, description = "application/sql") + /** An application-specific SQL query. Constant alias for string: `"application/sql"`. */ + @JvmField val APPLICATION_SQL = Encoding(JniEncoding.encodingApplicationSql()) - /** - * Constrained Application Protocol (CoAP) data intended for CoAP-to-HTTP and HTTP-to-CoAP proxies. - * - * Constant alias for string: `"application/coap-payload"`. - */ - @JvmField - val APPLICATION_COAP_PAYLOAD = Encoding(30, description = "application/coap-payload") + /** Constrained Application Protocol (CoAP) data intended for CoAP-to-HTTP and HTTP-to-CoAP proxies. Constant alias for string: `"application/coap-payload"`. */ + @JvmField val APPLICATION_COAP_PAYLOAD = Encoding(JniEncoding.encodingApplicationCoapPayload()) - /** - * Defines a JSON document structure for expressing a sequence of operations to apply to a JSON document. - * - * Constant alias for string: `"application/json-patch+json"`. - */ - @JvmField - val APPLICATION_JSON_PATCH_JSON = Encoding(31, description = "application/json-patch+json") + /** Defines a JSON document structure for expressing a sequence of operations to apply to a JSON document. Constant alias for string: `"application/json-patch+json"`. */ + @JvmField val APPLICATION_JSON_PATCH_JSON = Encoding(JniEncoding.encodingApplicationJsonPatchJson()) - /** - * A JSON text sequence consists of any number of JSON texts, all encoded in UTF-8. - * - * Constant alias for string: `"application/json-seq"`. - */ - @JvmField - val APPLICATION_JSON_SEQ = Encoding(32, description = "application/json-seq") + /** A JSON text sequence consists of any number of JSON texts, all encoded in UTF-8. Constant alias for string: `"application/json-seq"`. */ + @JvmField val APPLICATION_JSON_SEQ = Encoding(JniEncoding.encodingApplicationJsonSeq()) - /** - * A JSONPath defines a string syntax for selecting and extracting JSON values from within a given JSON value. - * - * Constant alias for string: `"application/jsonpath"`. - */ - @JvmField - val APPLICATION_JSONPATH = Encoding(33, description = "application/jsonpath") + /** A JSONPath defines a string syntax for selecting and extracting JSON values from within a given JSON value. Constant alias for string: `"application/jsonpath"`. */ + @JvmField val APPLICATION_JSONPATH = Encoding(JniEncoding.encodingApplicationJsonpath()) - /** - * A JSON Web Token (JWT). - * - * Constant alias for string: `"application/jwt"`. - */ - @JvmField - val APPLICATION_JWT = Encoding(34, description = "application/jwt") + /** A JSON Web Token (JWT). Constant alias for string: `"application/jwt"`. */ + @JvmField val APPLICATION_JWT = Encoding(JniEncoding.encodingApplicationJwt()) - /** - * An application-specific MPEG-4 encoded data, either audio or video. - * - * Constant alias for string: `"application/mp4"`. - */ - @JvmField - val APPLICATION_MP4 = Encoding(35, description = "application/mp4") + /** An application-specific MPEG-4 encoded data, either audio or video. Constant alias for string: `"application/mp4"`. */ + @JvmField val APPLICATION_MP4 = Encoding(JniEncoding.encodingApplicationMp4()) - /** - * A SOAP 1.2 message serialized as XML 1.0. - * - * Constant alias for string: `"application/soap+xml"`. - */ - @JvmField - val APPLICATION_SOAP_XML = Encoding(36, description = "application/soap+xml") + /** A SOAP 1.2 message serialized as XML 1.0. Constant alias for string: `"application/soap+xml"`. */ + @JvmField val APPLICATION_SOAP_XML = Encoding(JniEncoding.encodingApplicationSoapXml()) - /** - * A YANG-encoded data commonly used by the Network Configuration Protocol (NETCONF). - * - * Constant alias for string: `"application/yang"`. - */ - @JvmField - val APPLICATION_YANG = Encoding(37, description = "application/yang") + /** A YANG-encoded data commonly used by the Network Configuration Protocol (NETCONF). Constant alias for string: `"application/yang"`. */ + @JvmField val APPLICATION_YANG = Encoding(JniEncoding.encodingApplicationYang()) - /** - * A MPEG-4 Advanced Audio Coding (AAC) media. - * - * Constant alias for string: `"audio/aac"`. - */ - @JvmField - val AUDIO_AAC = Encoding(38, description = "audio/aac") + /** A MPEG-4 Advanced Audio Coding (AAC) media. Constant alias for string: `"audio/aac"`. */ + @JvmField val AUDIO_AAC = Encoding(JniEncoding.encodingAudioAac()) - /** - * A Free Lossless Audio Codec (FLAC) media. - * - * Constant alias for string: `"audio/flac"`. - */ - @JvmField - val AUDIO_FLAC = Encoding(39, description = "audio/flac") + /** A Free Lossless Audio Codec (FLAC) media. Constant alias for string: `"audio/flac"`. */ + @JvmField val AUDIO_FLAC = Encoding(JniEncoding.encodingAudioFlac()) - /** - * An audio codec defined in MPEG-1, MPEG-2, MPEG-4, or registered at the MP4 registration authority. - * - * Constant alias for string: `"audio/mp4"`. - */ - @JvmField - val AUDIO_MP4 = Encoding(40, description = "audio/mp4") + /** An audio codec defined in MPEG-1, MPEG-2, MPEG-4, or registered at the MP4 registration authority. Constant alias for string: `"audio/mp4"`. */ + @JvmField val AUDIO_MP4 = Encoding(JniEncoding.encodingAudioMp4()) - /** - * An Ogg-encapsulated audio stream. - * - * Constant alias for string: `"audio/ogg"`. - */ - @JvmField - val AUDIO_OGG = Encoding(41, description = "audio/ogg") + /** An Ogg-encapsulated audio stream. Constant alias for string: `"audio/ogg"`. */ + @JvmField val AUDIO_OGG = Encoding(JniEncoding.encodingAudioOgg()) - /** - * A Vorbis-encoded audio stream. - * - * Constant alias for string: `"audio/vorbis"`. - */ - @JvmField - val AUDIO_VORBIS = Encoding(42, description = "audio/vorbis") + /** A Vorbis-encoded audio stream. Constant alias for string: `"audio/vorbis"`. */ + @JvmField val AUDIO_VORBIS = Encoding(JniEncoding.encodingAudioVorbis()) - /** - * A h261-encoded video stream. - * - * Constant alias for string: `"video/h261"`. - */ - @JvmField - val VIDEO_H261 = Encoding(43, description = "video/h261") + /** A h261-encoded video stream. Constant alias for string: `"video/h261"`. */ + @JvmField val VIDEO_H261 = Encoding(JniEncoding.encodingVideoH261()) - /** - * A h263-encoded video stream. - * - * Constant alias for string: `"video/h263"`. - */ - @JvmField - val VIDEO_H263 = Encoding(44, description = "video/h263") + /** A h263-encoded video stream. Constant alias for string: `"video/h263"`. */ + @JvmField val VIDEO_H263 = Encoding(JniEncoding.encodingVideoH263()) - /** - * A h264-encoded video stream. - * - * Constant alias for string: `"video/h264"`. - */ - @JvmField - val VIDEO_H264 = Encoding(45, description = "video/h264") + /** A h264-encoded video stream. Constant alias for string: `"video/h264"`. */ + @JvmField val VIDEO_H264 = Encoding(JniEncoding.encodingVideoH264()) - /** - * A h265-encoded video stream. - * - * Constant alias for string: `"video/h265"`. - */ - @JvmField - val VIDEO_H265 = Encoding(46, description = "video/h265") + /** A h265-encoded video stream. Constant alias for string: `"video/h265"`. */ + @JvmField val VIDEO_H265 = Encoding(JniEncoding.encodingVideoH265()) - /** - * A h266-encoded video stream. - * - * Constant alias for string: `"video/h266"`. - */ - @JvmField - val VIDEO_H266 = Encoding(47, description = "video/h266") + /** A h266-encoded video stream. Constant alias for string: `"video/h266"`. */ + @JvmField val VIDEO_H266 = Encoding(JniEncoding.encodingVideoH266()) - /** - * A video codec defined in MPEG-1, MPEG-2, MPEG-4, or registered at the MP4 registration authority. - * - * Constant alias for string: `"video/mp4"`. - */ - @JvmField - val VIDEO_MP4 = Encoding(48, description = "video/mp4") + /** A video codec defined in MPEG-1, MPEG-2, MPEG-4, or registered at the MP4 registration authority. Constant alias for string: `"video/mp4"`. */ + @JvmField val VIDEO_MP4 = Encoding(JniEncoding.encodingVideoMp4()) - /** - * An Ogg-encapsulated video stream. - * - * Constant alias for string: `"video/ogg"`. - */ - @JvmField - val VIDEO_OGG = Encoding(49, description = "video/ogg") + /** An Ogg-encapsulated video stream. Constant alias for string: `"video/ogg"`. */ + @JvmField val VIDEO_OGG = Encoding(JniEncoding.encodingVideoOgg()) - /** - * An uncompressed, studio-quality video stream. - * - * Constant alias for string: `"video/raw"`. - */ - @JvmField - val VIDEO_RAW = Encoding(50, description = "video/raw") + /** An uncompressed, studio-quality video stream. Constant alias for string: `"video/raw"`. */ + @JvmField val VIDEO_RAW = Encoding(JniEncoding.encodingVideoRaw()) - /** - * A VP8-encoded video stream. - * - * Constant alias for string: `"video/vp8"`. - */ - @JvmField - val VIDEO_VP8 = Encoding(51, description = "video/vp8") + /** A VP8-encoded video stream. Constant alias for string: `"video/vp8"`. */ + @JvmField val VIDEO_VP8 = Encoding(JniEncoding.encodingVideoVp8()) - /** - * A VP9-encoded video stream. - * - * Constant alias for string: `"video/vp9"`. - */ - @JvmField - val VIDEO_VP9 = Encoding(52, description = "video/vp9") + /** A VP9-encoded video stream. Constant alias for string: `"video/vp9"`. */ + @JvmField val VIDEO_VP9 = Encoding(JniEncoding.encodingVideoVp9()) + + /** The default [Encoding] is [ZENOH_BYTES]. */ + @JvmStatic fun defaultEncoding() = ZENOH_BYTES /** - * The default [Encoding] is [ZENOH_BYTES]. + * Parse a textual encoding (e.g. `"text/plain"`, `"text/plain;utf-8"`, + * `"my_encoding"`). Well-known names resolve to their canonical id; + * everything else is preserved as a custom encoding. */ - @JvmStatic - fun defaultEncoding() = ZENOH_BYTES + @JvmStatic fun from(s: String): Encoding = Encoding(JniEncoding.encodingFromString(s)) } /** * Set a schema to this encoding. Zenoh does not define what a schema is and its semantics is left to the implementer. * E.g. a common schema for `text/plain` encoding is `utf-8`. */ - fun withSchema(schema: String): Encoding { - return Encoding(this.id, schema, this.description) - } + fun withSchema(schema: String): Encoding = + Encoding(JniEncoding(inner.id, schema)) - override fun toString(): String { - val base = description ?: "unknown(${this.id})" - val schemaInfo = schema?.let { ";$it" } ?: "" - return "$base$schemaInfo" - } + private val cachedString: String by lazy { inner.encodingToString() } + + override fun toString(): String = cachedString override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false - other as Encoding - + // Compare leaves directly — avoids forcing the lazy JniEncoding build. return id == other.id && schema == other.schema } - override fun hashCode(): Int { - return id.hashCode() - } + override fun hashCode(): Int = 31 * id + (schema?.hashCode() ?: 0) + + internal fun toFlat(): JniEncoding = inner } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt index 1fd22d7c..50163b04 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/bytes/ZBytes.kt @@ -30,7 +30,7 @@ package io.zenoh.bytes * flatbuffers, etc. * */ -class ZBytes internal constructor(internal val bytes: ByteArray) : IntoZBytes { +class ZBytes internal constructor(internal val inner: io.zenoh.jni.bytes.ZBytes) : IntoZBytes { companion object { @@ -38,32 +38,32 @@ class ZBytes internal constructor(internal val bytes: ByteArray) : IntoZBytes { * Creates a [ZBytes] instance from a [String]. */ @JvmStatic - fun from(string: String) = ZBytes(string.encodeToByteArray()) + fun from(string: String) = ZBytes(io.zenoh.jni.bytes.ZBytes(string.encodeToByteArray())) /** * Creates a [ZBytes] instance from a [ByteArray]. */ @JvmStatic - fun from(bytes: ByteArray) = ZBytes(bytes) + fun from(bytes: ByteArray) = ZBytes(io.zenoh.jni.bytes.ZBytes(bytes)) } /** Returns the internal byte representation of the [ZBytes]. */ - fun toBytes(): ByteArray = bytes + fun toBytes(): ByteArray = inner.bytes /** Attempts to decode the [ZBytes] into a string with UTF-8 encoding. */ @Throws fun tryToString(): String = - bytes.decodeToString(throwOnInvalidSequence = true) + inner.bytes.decodeToString(throwOnInvalidSequence = true) - override fun toString(): String = bytes.decodeToString() + override fun toString(): String = inner.bytes.decodeToString() override fun into(): ZBytes = this - override fun equals(other: Any?) = other is ZBytes && bytes.contentEquals(other.bytes) + override fun equals(other: Any?) = other is ZBytes && inner.bytes.contentEquals(other.inner.bytes) - override fun hashCode() = bytes.contentHashCode() + override fun hashCode() = inner.bytes.contentHashCode() } internal fun ByteArray.into(): ZBytes { - return ZBytes(this) + return ZBytes(io.zenoh.jni.bytes.ZBytes(this)) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/config/WhatAmI.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/config/WhatAmI.kt index 983c9221..c6d3161c 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/config/WhatAmI.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/config/WhatAmI.kt @@ -19,12 +19,12 @@ package io.zenoh.config * * The role of the node sending the `hello` message. */ -enum class WhatAmI(internal val value: Int) { - Router(1), - Peer(2), - Client(4); +enum class WhatAmI(internal val jni: io.zenoh.jni.config.WhatAmI) { + Router(io.zenoh.jni.config.WhatAmI.ROUTER), + Peer(io.zenoh.jni.config.WhatAmI.PEER), + Client(io.zenoh.jni.config.WhatAmI.CLIENT); companion object { - internal fun fromInt(value: Int) = entries.first { value == it.value } + internal fun fromJni(jni: io.zenoh.jni.config.WhatAmI): WhatAmI = entries.first { it.jni == jni } } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt index 9787fced..6c8212d1 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/config/ZenohId.kt @@ -14,16 +14,15 @@ package io.zenoh.config -import io.zenoh.jni.JNIZenohId import kotlin.math.absoluteValue /** * The global unique id of a Zenoh peer. */ -data class ZenohId internal constructor(internal val bytes: ByteArray) { +data class ZenohId internal constructor(internal val inner: io.zenoh.jni.config.ZenohId) { override fun toString(): String { - return JNIZenohId.toStringViaJNI(bytes) + return io.zenoh.jni.config.ZenohId.zenohIdToString(inner.bytes) } override fun equals(other: Any?): Boolean { @@ -32,11 +31,11 @@ data class ZenohId internal constructor(internal val bytes: ByteArray) { other as ZenohId - return bytes.contentEquals(other.bytes) + return inner.bytes.contentEquals(other.inner.bytes) } override fun hashCode(): Int { - return bytes.contentHashCode() + return inner.bytes.contentHashCode() } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIExceptionWrapping.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIExceptionWrapping.kt new file mode 100644 index 00000000..e40c34e8 --- /dev/null +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIExceptionWrapping.kt @@ -0,0 +1,29 @@ +// +// Copyright (c) 2026 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +package io.zenoh.exceptions + +/** + * Run [block], translating flat-jni exceptions into [ZError] so callers keep + * the zenoh-java exception surface stable during migration. + */ +internal inline fun wrapJNIExceptionAsZError(block: () -> T): T { + return try { + block() + } catch (e: io.zenoh.jni.Error) { + throw ZError(e.message) + } catch (e: io.zenoh.jni.JniBindingError) { + throw ZError(e.message) + } +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserializer.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserializer.kt index 1d039cbe..9eb66ece 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserializer.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZDeserializer.kt @@ -17,7 +17,7 @@ package io.zenoh.ext import com.google.common.reflect.TypeToken import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes -import io.zenoh.jni.JNIZBytes +import io.zenoh.jni.bytes.deserializeViaJNI /** * Zenoh deserializer. @@ -106,6 +106,6 @@ abstract class ZDeserializer: TypeToken() { */ fun deserialize(zbytes: IntoZBytes): T { @Suppress("UNCHECKED_CAST") - return JNIZBytes.deserializeViaJNI(zbytes.into(), this.type) as T + return deserializeViaJNI(zbytes.into().inner.bytes, this.type) as T } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerializer.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerializer.kt index 8ee4a1b7..769c11e7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerializer.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/ext/ZSerializer.kt @@ -16,7 +16,7 @@ package io.zenoh.ext import com.google.common.reflect.TypeToken import io.zenoh.bytes.ZBytes -import io.zenoh.jni.JNIZBytes +import io.zenoh.jni.bytes.serializeViaJNI /** * Zenoh serializer. @@ -104,6 +104,6 @@ abstract class ZSerializer: TypeToken() { * Serialize [t] into a [ZBytes]. */ fun serialize(t: T): ZBytes { - return JNIZBytes.serializeViaJNI(t as Any, this.type) + return ZBytes.from(serializeViaJNI(t as Any, this.type)) } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt deleted file mode 100644 index ea278988..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt +++ /dev/null @@ -1,101 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -import io.zenoh.Config -import io.zenoh.ZenohLoad -import io.zenoh.exceptions.ZError -import java.io.File -import java.nio.file.Path - -internal class JNIConfig(internal val ptr: Long) { - - companion object { - - init { - ZenohLoad - } - - fun loadDefaultConfig(): Config { - val cfgPtr = loadDefaultConfigViaJNI() - return Config(JNIConfig(cfgPtr)) - } - - @Throws(ZError::class) - fun loadConfigFile(path: Path): Config { - val cfgPtr = loadConfigFileViaJNI(path.toString()) - return Config(JNIConfig(cfgPtr)) - } - - @Throws(ZError::class) - fun loadConfigFile(file: File): Config = loadConfigFile(file.toPath()) - - @Throws(ZError::class) - fun loadJsonConfig(rawConfig: String): Config { - val cfgPtr = loadJsonConfigViaJNI(rawConfig) - return Config(JNIConfig(cfgPtr)) - } - - @Throws(ZError::class) - fun loadJson5Config(rawConfig: String): Config { - val cfgPtr = loadJsonConfigViaJNI(rawConfig) - return Config(JNIConfig(cfgPtr)) - } - - @Throws(ZError::class) - fun loadYamlConfig(rawConfig: String): Config { - val cfgPtr = loadYamlConfigViaJNI(rawConfig) - return Config(JNIConfig(cfgPtr)) - } - - @Throws(ZError::class) - private external fun loadDefaultConfigViaJNI(): Long - - @Throws(ZError::class) - private external fun loadConfigFileViaJNI(path: String): Long - - @Throws(ZError::class) - private external fun loadJsonConfigViaJNI(rawConfig: String): Long - - @Throws(ZError::class) - private external fun loadYamlConfigViaJNI(rawConfig: String): Long - - @Throws(ZError::class) - private external fun getIdViaJNI(ptr: Long): ByteArray - - @Throws(ZError::class) - private external fun insertJson5ViaJNI(ptr: Long, key: String, value: String): Long - - /** Frees the underlying native config. */ - private external fun freePtrViaJNI(ptr: Long) - - @Throws(ZError::class) - private external fun getJsonViaJNI(ptr: Long, key: String): String - } - - fun close() { - freePtrViaJNI(ptr) - } - - @Throws(ZError::class) - fun getJson(key: String): String { - return getJsonViaJNI(ptr, key) - } - - @Throws(ZError::class) - fun insertJson5(key: String, value: String) { - insertJson5ViaJNI(this.ptr, key, value) - } -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt deleted file mode 100644 index 29e419e3..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt +++ /dev/null @@ -1,104 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -import io.zenoh.ZenohLoad -import io.zenoh.exceptions.ZError -import io.zenoh.keyexpr.KeyExpr -import io.zenoh.keyexpr.SetIntersectionLevel - -internal class JNIKeyExpr(internal val ptr: Long) { - - companion object { - init { - ZenohLoad - } - - @Throws(ZError::class) - fun tryFrom(keyExpr: String): KeyExpr { - return KeyExpr(tryFromViaJNI(keyExpr)) - } - - @Throws(ZError::class) - fun autocanonize(keyExpr: String): KeyExpr { - return KeyExpr(autocanonizeViaJNI(keyExpr)) - } - - @Throws(ZError::class) - fun intersects(keyExprA: KeyExpr, keyExprB: KeyExpr): Boolean = intersectsViaJNI( - keyExprA.jniKeyExpr?.ptr ?: 0, - keyExprA.keyExpr, - keyExprB.jniKeyExpr?.ptr ?: 0, - keyExprB.keyExpr - ) - - @Throws(ZError::class) - fun includes(keyExprA: KeyExpr, keyExprB: KeyExpr): Boolean = includesViaJNI( - keyExprA.jniKeyExpr?.ptr ?: 0, - keyExprA.keyExpr, - keyExprB.jniKeyExpr?.ptr ?: 0, - keyExprB.keyExpr - ) - - @Throws(ZError::class) - fun relationTo(keyExpr: KeyExpr, other: KeyExpr): SetIntersectionLevel { - val intersection = relationToViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - other.jniKeyExpr?.ptr ?: 0, - other.keyExpr - ) - return SetIntersectionLevel.fromInt(intersection) - } - - @Throws(ZError::class) - fun joinViaJNI(keyExpr: KeyExpr, other: String): KeyExpr { - return KeyExpr(joinViaJNI(keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, other)) - } - - @Throws(ZError::class) - fun concatViaJNI(keyExpr: KeyExpr, other: String): KeyExpr { - return KeyExpr(concatViaJNI(keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, other)) - } - - @Throws(ZError::class) - private external fun tryFromViaJNI(keyExpr: String): String - - @Throws(ZError::class) - private external fun autocanonizeViaJNI(keyExpr: String): String - - @Throws(ZError::class) - private external fun intersectsViaJNI(ptrA: Long, keyExprA: String, ptrB: Long, keyExprB: String): Boolean - - @Throws(ZError::class) - private external fun includesViaJNI(ptrA: Long, keyExprA: String, ptrB: Long, keyExprB: String): Boolean - - @Throws(ZError::class) - private external fun relationToViaJNI(ptrA: Long, keyExprA: String, ptrB: Long, keyExprB: String): Int - - @Throws(ZError::class) - private external fun joinViaJNI(ptrA: Long, keyExprA: String, other: String): String - - @Throws(ZError::class) - private external fun concatViaJNI(ptrA: Long, keyExprA: String, other: String): String - } - - fun close() { - freePtrViaJNI(ptr) - } - - /** Frees the underlying native KeyExpr. */ - private external fun freePtrViaJNI(ptr: Long) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt deleted file mode 100644 index 0225c32b..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILiveliness.kt +++ /dev/null @@ -1,188 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -import io.zenoh.bytes.Encoding -import io.zenoh.bytes.into -import io.zenoh.config.EntityGlobalId -import io.zenoh.config.ZenohId -import io.zenoh.exceptions.ZError -import io.zenoh.handlers.Callback -import io.zenoh.jni.callbacks.JNIGetCallback -import io.zenoh.jni.callbacks.JNIOnCloseCallback -import io.zenoh.jni.callbacks.JNISubscriberCallback -import io.zenoh.keyexpr.KeyExpr -import io.zenoh.liveliness.LivelinessToken -import io.zenoh.pubsub.CallbackSubscriber -import io.zenoh.pubsub.HandlerSubscriber -import io.zenoh.qos.CongestionControl -import io.zenoh.qos.Priority -import io.zenoh.qos.QoS -import io.zenoh.query.Reply -import io.zenoh.sample.Sample -import io.zenoh.sample.SampleKind -import org.apache.commons.net.ntp.TimeStamp -import java.time.Duration - -internal object JNILiveliness { - - @Throws(ZError::class) - fun get( - jniSession: JNISession, - keyExpr: KeyExpr, - callback: Callback, - receiver: R, - timeout: Duration, - onClose: Runnable - ): R { - val getCallback = JNIGetCallback { - replierZid: ByteArray?, - replierEid: Int, - success: Boolean, - keyExpr2: String?, - payload: ByteArray, - encodingId: Int, - encodingSchema: String?, - kind: Int, - timestampNTP64: Long, - timestampIsValid: Boolean, - attachmentBytes: ByteArray?, - express: Boolean, - priority: Int, - congestionControl: Int, - -> - val reply: Reply - if (success) { - val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null - val sample = Sample( - KeyExpr(keyExpr2!!, null), - payload.into(), - Encoding(encodingId, schema = encodingSchema), - SampleKind.fromInt(kind), - timestamp, - QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), - attachmentBytes?.into() - ) - reply = Reply.Success(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, sample) - } else { - reply = Reply.Error( - replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, - payload.into(), - Encoding(encodingId, schema = encodingSchema) - ) - } - callback.run(reply) - } - getViaJNI( - jniSession.sessionPtr, - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - getCallback, - timeout.toMillis(), - onClose::run - ) - return receiver - } - - fun declareToken(jniSession: JNISession, keyExpr: KeyExpr): LivelinessToken { - val ptr = declareTokenViaJNI(jniSession.sessionPtr, keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr) - return LivelinessToken(JNILivelinessToken(ptr)) - } - - fun declareSubscriber( - jniSession: JNISession, - keyExpr: KeyExpr, - callback: Callback, - history: Boolean, - onClose: () -> Unit - ): CallbackSubscriber { - val subCallback = - JNISubscriberCallback { keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> - val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null - val sample = Sample( - KeyExpr(keyExpr2, null), - payload.into(), - Encoding(encodingId, schema = encodingSchema), - SampleKind.fromInt(kind), - timestamp, - QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), - attachmentBytes?.into() - ) - callback.run(sample) - } - val ptr = declareSubscriberViaJNI( - jniSession.sessionPtr, - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - subCallback, - history, - onClose - ) - return CallbackSubscriber(keyExpr, JNISubscriber(ptr)) - } - - fun declareSubscriber( - jniSession: JNISession, - keyExpr: KeyExpr, - callback: Callback, - receiver: R, - history: Boolean, - onClose: () -> Unit - ): HandlerSubscriber { - val subCallback = - JNISubscriberCallback { keyExpr2, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> - val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null - val sample = Sample( - KeyExpr(keyExpr2, null), - payload.into(), - Encoding(encodingId, schema = encodingSchema), - SampleKind.fromInt(kind), - timestamp, - QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), - attachmentBytes?.into() - ) - callback.run(sample) - } - val ptr = declareSubscriberViaJNI( - jniSession.sessionPtr, - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - subCallback, - history, - onClose - ) - return HandlerSubscriber(keyExpr, JNISubscriber(ptr), receiver) - } - - private external fun getViaJNI( - sessionPtr: Long, - keyExprPtr: Long, - keyExprString: String, - callback: JNIGetCallback, - timeoutMs: Long, - onClose: JNIOnCloseCallback - ) - - private external fun declareTokenViaJNI(sessionPtr: Long, keyExprPtr: Long, keyExprString: String): Long - - private external fun declareSubscriberViaJNI( - sessionPtr: Long, - keyExprPtr: Long, - keyExprString: String, - callback: JNISubscriberCallback, - history: Boolean, - onClose: JNIOnCloseCallback - ): Long -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt deleted file mode 100644 index 991c860a..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.zenoh.jni - -internal class JNILivelinessToken(val ptr: Long) { - - fun undeclare() { - undeclareViaJNI(this.ptr) - } - - companion object { - external fun undeclareViaJNI(ptr: Long) - } -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt deleted file mode 100644 index 6e694271..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -import io.zenoh.exceptions.ZError -import io.zenoh.bytes.Encoding -import io.zenoh.bytes.IntoZBytes - -/** - * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.pubsub.Publisher]. - * - * @property ptr: raw pointer to the underlying native Publisher. - */ -internal class JNIPublisher(private val ptr: Long) { - - /** - * Put operation. - * - * @param payload Payload of the put. - * @param encoding Encoding of the payload. - * @param attachment Optional attachment. - */ - @Throws(ZError::class) - fun put(payload: IntoZBytes, encoding: Encoding?, attachment: IntoZBytes?) { - val resolvedEncoding = encoding ?: Encoding.defaultEncoding() - putViaJNI(payload.into().bytes, resolvedEncoding.id, resolvedEncoding.schema, attachment?.into()?.bytes, ptr) - } - - /** - * Delete operation. - * - * @param attachment Optional attachment. - */ - @Throws(ZError::class) - fun delete(attachment: IntoZBytes?) { - deleteViaJNI(attachment?.into()?.bytes, ptr) - } - - /** - * Close and free the underlying publisher pointer. - * - * Further operations with this publisher should not be performed anymore. - */ - fun close() { - freePtrViaJNI(ptr) - } - - @Throws(ZError::class) - private external fun putViaJNI( - valuePayload: ByteArray, encodingId: Int, encodingSchema: String?, attachment: ByteArray?, ptr: Long - ) - - @Throws(ZError::class) - private external fun deleteViaJNI(attachment: ByteArray?, ptr: Long) - - private external fun freePtrViaJNI(ptr: Long) - -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuerier.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuerier.kt deleted file mode 100644 index c026ed1c..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuerier.kt +++ /dev/null @@ -1,137 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -import io.zenoh.annotations.Unstable -import io.zenoh.bytes.Encoding -import io.zenoh.bytes.IntoZBytes -import io.zenoh.bytes.into -import io.zenoh.config.EntityGlobalId -import io.zenoh.config.ZenohId -import io.zenoh.exceptions.ZError -import io.zenoh.handlers.Callback -import io.zenoh.handlers.Handler -import io.zenoh.jni.callbacks.JNIGetCallback -import io.zenoh.jni.callbacks.JNIOnCloseCallback -import io.zenoh.keyexpr.KeyExpr -import io.zenoh.qos.CongestionControl -import io.zenoh.qos.Priority -import io.zenoh.qos.QoS -import io.zenoh.query.Parameters -import io.zenoh.query.Querier -import io.zenoh.query.Reply -import io.zenoh.sample.Sample -import io.zenoh.sample.SampleKind -import org.apache.commons.net.ntp.TimeStamp - -internal class JNIQuerier(val ptr: Long) { - - @OptIn(Unstable::class) - @Throws(ZError::class) - fun performGetWithCallback(keyExpr: KeyExpr, callback: Callback, options: Querier.GetOptions) { - performGet(keyExpr, options.parameters, callback, fun() {}, Unit, options.attachment, options.payload, options.encoding) - } - - @OptIn(Unstable::class) - @Throws(ZError::class) - fun performGetWithHandler(keyExpr: KeyExpr, handler: Handler, options: Querier.GetOptions): R { - return performGet(keyExpr, options.parameters, handler::handle, handler::onClose, handler.receiver(), options.attachment, options.payload, options.encoding) - } - - @Throws(ZError::class) - private fun performGet( - keyExpr: KeyExpr, - parameters: Parameters?, - callback: Callback, - onClose: () -> Unit, - receiver: R, - attachment: IntoZBytes?, - payload: IntoZBytes?, - encoding: Encoding? - ): R { - val getCallback = JNIGetCallback { - replierZid: ByteArray?, - replierEid: Int, - success: Boolean, - keyExpr2: String?, - payload2: ByteArray, - encodingId: Int, - encodingSchema: String?, - kind: Int, - timestampNTP64: Long, - timestampIsValid: Boolean, - attachmentBytes: ByteArray?, - express: Boolean, - priority: Int, - congestionControl: Int, - -> - val reply: Reply - if (success) { - val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null - val sample = Sample( - KeyExpr(keyExpr2!!, null), - payload2.into(), - Encoding(encodingId, schema = encodingSchema), - SampleKind.fromInt(kind), - timestamp, - QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), - attachmentBytes?.into() - ) - reply = Reply.Success(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, sample) - } else { - reply = Reply.Error( - replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, - payload2.into(), - Encoding(encodingId, schema = encodingSchema) - ) - } - callback.run(reply) - } - - getViaJNI(this.ptr, - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - parameters?.toString(), - getCallback, - onClose, - attachment?.into()?.bytes, - payload?.into()?.bytes, - encoding?.id ?: Encoding.defaultEncoding().id, - encoding?.schema - ) - return receiver - } - - fun close() { - freePtrViaJNI(ptr) - } - - @Throws(ZError::class) - private external fun getViaJNI( - querierPtr: Long, - keyExprPtr: Long, - keyExprString: String, - parameters: String?, - callback: JNIGetCallback, - onClose: JNIOnCloseCallback, - attachmentBytes: ByteArray?, - payload: ByteArray?, - encodingId: Int, - encodingSchema: String?, - ) - - private external fun freePtrViaJNI(ptr: Long) - -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt deleted file mode 100644 index 0b1683f0..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQuery.kt +++ /dev/null @@ -1,106 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -import io.zenoh.exceptions.ZError -import io.zenoh.keyexpr.KeyExpr -import io.zenoh.bytes.Encoding -import io.zenoh.qos.QoS -import io.zenoh.bytes.IntoZBytes -import io.zenoh.sample.Sample -import org.apache.commons.net.ntp.TimeStamp - -/** - * Adapter class for interacting with a Query using JNI. - * - * This class serves as an adapter for interacting with a Query through JNI (Java Native Interface). - * - * @property ptr The raw pointer to the underlying native query. - */ -internal class JNIQuery(private val ptr: Long) { - - fun replySuccess(sample: Sample) { - val timestampEnabled = sample.timestamp != null - replySuccessViaJNI( - ptr, - sample.keyExpr.jniKeyExpr?.ptr ?: 0, - sample.keyExpr.keyExpr, - sample.payload.bytes, - sample.encoding.id, - sample.encoding.schema, - timestampEnabled, - if (timestampEnabled) sample.timestamp!!.ntpValue() else 0, - sample.attachment?.bytes, - sample.qos.express - ) - } - - fun replyError(error: IntoZBytes, encoding: Encoding) { - replyErrorViaJNI(ptr, error.into().bytes, encoding.id, encoding.schema) - } - - fun replyDelete(keyExpr: KeyExpr, timestamp: TimeStamp?, attachment: IntoZBytes?, qos: QoS) { - val timestampEnabled = timestamp != null - replyDeleteViaJNI( - ptr, - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - timestampEnabled, - if (timestampEnabled) timestamp!!.ntpValue() else 0, - attachment?.into()?.bytes, - qos.express - ) - } - - fun close() { - freePtrViaJNI(ptr) - } - - @Throws(ZError::class) - private external fun replySuccessViaJNI( - queryPtr: Long, - keyExprPtr: Long, - keyExprString: String, - valuePayload: ByteArray, - valueEncodingId: Int, - valueEncodingSchema: String?, - timestampEnabled: Boolean, - timestampNtp64: Long, - attachment: ByteArray?, - qosExpress: Boolean, - ) - - @Throws(ZError::class) - private external fun replyErrorViaJNI( - queryPtr: Long, - errorValuePayload: ByteArray, - errorValueEncoding: Int, - encodingSchema: String?, - ) - - @Throws(ZError::class) - private external fun replyDeleteViaJNI( - queryPtr: Long, - keyExprPtr: Long, - keyExprString: String, - timestampEnabled: Boolean, - timestampNtp64: Long, - attachment: ByteArray?, - qosExpress: Boolean, - ) - - /** Frees the underlying native Query. */ - private external fun freePtrViaJNI(ptr: Long) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt deleted file mode 100644 index e5f7d3ce..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIQueryable.kt +++ /dev/null @@ -1,30 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -/** - * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.query.Queryable] - * - * @property ptr: raw pointer to the underlying native Queryable. - */ -internal class JNIQueryable(val ptr: Long) { - - fun close() { - freePtrViaJNI(ptr) - } - - /** Frees the underlying native Queryable. */ - private external fun freePtrViaJNI(ptr: Long) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt deleted file mode 100644 index f2e1c49c..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIScout.kt +++ /dev/null @@ -1,87 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -import io.zenoh.Config -import io.zenoh.ZenohLoad -import io.zenoh.exceptions.ZError -import io.zenoh.handlers.Callback -import io.zenoh.jni.callbacks.JNIScoutCallback -import io.zenoh.config.ZenohId -import io.zenoh.scouting.Hello -import io.zenoh.config.WhatAmI -import io.zenoh.jni.callbacks.JNIOnCloseCallback -import io.zenoh.scouting.CallbackScout -import io.zenoh.scouting.HandlerScout - -/** - * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.scouting.Scout] - * - * @property ptr: raw pointer to the underlying native scout. - */ -internal class JNIScout(private val ptr: Long) { - - companion object { - - init { - ZenohLoad - } - - @Throws(ZError::class) - fun scoutWithHandler( - whatAmI: Set, - callback: Callback, - onClose: () -> Unit, - config: Config?, - receiver: R - ): HandlerScout { - val scoutCallback = JNIScoutCallback { whatAmI2: Int, id: ByteArray, locators: List -> - callback.run(Hello(WhatAmI.fromInt(whatAmI2), ZenohId(id), locators)) - } - val binaryWhatAmI: Int = whatAmI.map { it.value }.reduce { acc, it -> acc or it } - val ptr = scoutViaJNI(binaryWhatAmI, scoutCallback, onClose,config?.jniConfig?.ptr ?: 0) - return HandlerScout(JNIScout(ptr), receiver) - } - - @Throws(ZError::class) - fun scoutWithCallback( - whatAmI: Set, - callback: Callback, - config: Config?, - ): CallbackScout { - val scoutCallback = JNIScoutCallback { whatAmI2: Int, id: ByteArray, locators: List -> - callback.run(Hello(WhatAmI.fromInt(whatAmI2), ZenohId(id), locators)) - } - val binaryWhatAmI: Int = whatAmI.map { it.value }.reduce { acc, it -> acc or it } - val ptr = scoutViaJNI(binaryWhatAmI, scoutCallback, fun() {},config?.jniConfig?.ptr ?: 0) - return CallbackScout(JNIScout(ptr)) - } - - @Throws(ZError::class) - private external fun scoutViaJNI( - whatAmI: Int, - callback: JNIScoutCallback, - onClose: JNIOnCloseCallback, - configPtr: Long, - ): Long - - @Throws(ZError::class) - external fun freePtrViaJNI(ptr: Long) - } - - fun close() { - freePtrViaJNI(ptr) - } -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt deleted file mode 100644 index 096a6c59..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISession.kt +++ /dev/null @@ -1,548 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -import io.zenoh.* -import io.zenoh.bytes.Encoding -import io.zenoh.exceptions.ZError -import io.zenoh.handlers.Callback -import io.zenoh.jni.callbacks.JNIOnCloseCallback -import io.zenoh.jni.callbacks.JNIGetCallback -import io.zenoh.jni.callbacks.JNIQueryableCallback -import io.zenoh.jni.callbacks.JNISubscriberCallback -import io.zenoh.keyexpr.KeyExpr -import io.zenoh.bytes.IntoZBytes -import io.zenoh.config.ZenohId -import io.zenoh.bytes.into -import io.zenoh.Config -import io.zenoh.annotations.Unstable -import io.zenoh.config.EntityGlobalId -import io.zenoh.handlers.Handler -import io.zenoh.pubsub.* -import io.zenoh.qos.CongestionControl -import io.zenoh.qos.Priority -import io.zenoh.qos.QoS -import io.zenoh.query.* -import io.zenoh.sample.Sample -import io.zenoh.sample.SampleKind -import org.apache.commons.net.ntp.TimeStamp - -/** Adapter class to handle the communication with the Zenoh JNI code for a [Session]. */ -internal class JNISession(val sessionPtr: Long) { - - companion object { - init { - ZenohLoad - } - - @Throws(ZError::class) - fun open(config: Config): JNISession { - val sessionPtr = openSessionViaJNI(config.jniConfig.ptr) - return JNISession(sessionPtr) - } - - @Throws(ZError::class) - private external fun openSessionViaJNI(configPtr: Long): Long - } - - fun close() { - closeSessionViaJNI(sessionPtr) - } - - @Throws(ZError::class) - fun declarePublisher(keyExpr: KeyExpr, publisherOptions: PublisherOptions): Publisher { - val publisherRawPtr = declarePublisherViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - sessionPtr, - publisherOptions.congestionControl.value, - publisherOptions.priority.value, - publisherOptions.express, - publisherOptions.reliability.ordinal - ) - return Publisher( - keyExpr, - publisherOptions.congestionControl, - publisherOptions.priority, - publisherOptions.encoding, - JNIPublisher(publisherRawPtr), - ) - } - - @Throws(ZError::class) - fun declareSubscriberWithHandler( - keyExpr: KeyExpr, handler: Handler - ): HandlerSubscriber { - val subCallback = - JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> - val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null - val sample = Sample( - KeyExpr(keyExpr1, null), - payload.into(), - Encoding(encodingId, schema = encodingSchema), - SampleKind.fromInt(kind), - timestamp, - QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), - attachmentBytes?.into() - ) - handler.handle(sample) - } - val subscriberRawPtr = declareSubscriberViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, keyExpr.keyExpr, sessionPtr, subCallback, handler::onClose - ) - return HandlerSubscriber(keyExpr, JNISubscriber(subscriberRawPtr), handler.receiver()) - } - - @Throws(ZError::class) - fun declareSubscriberWithCallback( - keyExpr: KeyExpr, callback: Callback - ): CallbackSubscriber { - val subCallback = - JNISubscriberCallback { keyExpr1, payload, encodingId, encodingSchema, kind, timestampNTP64, timestampIsValid, attachmentBytes, express: Boolean, priority: Int, congestionControl: Int -> - val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null - val sample = Sample( - KeyExpr(keyExpr1, null), - payload.into(), - Encoding(encodingId, schema = encodingSchema), - SampleKind.fromInt(kind), - timestamp, - QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), - attachmentBytes?.into() - ) - callback.run(sample) - } - val subscriberRawPtr = declareSubscriberViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - sessionPtr, - subCallback, - fun() {} - ) - return CallbackSubscriber(keyExpr, JNISubscriber(subscriberRawPtr)) - } - - @Throws(ZError::class) - fun declareQueryableWithCallback( - keyExpr: KeyExpr, callback: Callback, config: QueryableOptions - ): CallbackQueryable { - val queryCallback = - JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long, acceptReplies: Int -> - val jniQuery = JNIQuery(queryPtr) - val keyExpr2 = KeyExpr(keyExpr1, null) - val selector = if (selectorParams.isEmpty()) { - Selector(keyExpr2) - } else { - Selector(keyExpr2, Parameters.from(selectorParams)) - } - val replyKeyExpr = ReplyKeyExpr.entries[acceptReplies] - val query = Query( - keyExpr2, - selector, - payload?.into(), - payload?.let { Encoding(encodingId, schema = encodingSchema) }, - attachmentBytes?.into(), - replyKeyExpr, - jniQuery - ) - callback.run(query) - } - val queryableRawPtr = declareQueryableViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - sessionPtr, - queryCallback, - fun() {}, - config.complete - ) - return CallbackQueryable(keyExpr, JNIQueryable(queryableRawPtr)) - } - - @Throws(ZError::class) - fun declareQueryableWithHandler( - keyExpr: KeyExpr, handler: Handler, config: QueryableOptions - ): HandlerQueryable { - val queryCallback = - JNIQueryableCallback { keyExpr1: String, selectorParams: String, payload: ByteArray?, encodingId: Int, encodingSchema: String?, attachmentBytes: ByteArray?, queryPtr: Long, acceptReplies: Int -> - val jniQuery = JNIQuery(queryPtr) - val keyExpr2 = KeyExpr(keyExpr1, null) - val selector = if (selectorParams.isEmpty()) { - Selector(keyExpr2) - } else { - Selector(keyExpr2, Parameters.from(selectorParams)) - } - val replyKeyExpr = ReplyKeyExpr.entries[acceptReplies] - val query = Query( - keyExpr2, - selector, - payload?.into(), - payload?.let { Encoding(encodingId, schema = encodingSchema) }, - attachmentBytes?.into(), - replyKeyExpr, - jniQuery - ) - handler.handle(query) - } - val queryableRawPtr = declareQueryableViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - sessionPtr, - queryCallback, - handler::onClose, - config.complete - ) - return HandlerQueryable(keyExpr, JNIQueryable(queryableRawPtr), handler.receiver()) - } - - @OptIn(Unstable::class) - fun declareQuerier( - keyExpr: KeyExpr, - options: QuerierOptions - ): Querier { - val querierRawPtr = declareQuerierViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - sessionPtr, - options.target.ordinal, - options.consolidationMode.ordinal, - options.congestionControl.value, - options.priority.value, - options.express, - options.timeout.toMillis(), - options.acceptReplies.ordinal - ) - return Querier( - keyExpr, - QoS( - congestionControl = options.congestionControl, - priority = options.priority, - express = options.express - ), - JNIQuerier(querierRawPtr) - ) - } - - @Throws(ZError::class) - fun performGetWithCallback( - intoSelector: IntoSelector, - callback: Callback, - options: GetOptions - ) { - val getCallback = JNIGetCallback { - replierZid: ByteArray?, - replierEid: Int, - success: Boolean, - keyExpr: String?, - payload1: ByteArray, - encodingId: Int, - encodingSchema: String?, - kind: Int, - timestampNTP64: Long, - timestampIsValid: Boolean, - attachmentBytes: ByteArray?, - express: Boolean, - priority: Int, - congestionControl: Int, - -> - val reply: Reply - if (success) { - val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null - val sample = Sample( - KeyExpr(keyExpr!!, null), - payload1.into(), - Encoding(encodingId, schema = encodingSchema), - SampleKind.fromInt(kind), - timestamp, - QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), - attachmentBytes?.into() - ) - reply = Reply.Success(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, sample) - } else { - reply = Reply.Error( - replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, - payload1.into(), - Encoding(encodingId, schema = encodingSchema) - ) - } - callback.run(reply) - } - - val selector = intoSelector.into() - getViaJNI( - selector.keyExpr.jniKeyExpr?.ptr ?: 0, - selector.keyExpr.keyExpr, - selector.parameters?.toString(), - sessionPtr, - getCallback, - fun() {}, - options.timeout.toMillis(), - options.target.ordinal, - options.consolidation.ordinal, - options.attachment?.into()?.bytes, - options.payload?.into()?.bytes, - options.encoding?.id ?: Encoding.defaultEncoding().id, - options.encoding?.schema, - options.qos.congestionControl.value, - options.qos.priority.value, - options.qos.express, - options.acceptReplies.ordinal - ) - } - - @Throws(ZError::class) - fun performGetWithHandler( - intoSelector: IntoSelector, - handler: Handler, - options: GetOptions - ): R { - val getCallback = JNIGetCallback { - replierZid: ByteArray?, - replierEid: Int, - success: Boolean, - keyExpr: String?, - payload1: ByteArray, - encodingId: Int, - encodingSchema: String?, - kind: Int, - timestampNTP64: Long, - timestampIsValid: Boolean, - attachmentBytes: ByteArray?, - express: Boolean, - priority: Int, - congestionControl: Int, - -> - val reply: Reply - if (success) { - val timestamp = if (timestampIsValid) TimeStamp(timestampNTP64) else null - val sample = Sample( - KeyExpr(keyExpr!!, null), - payload1.into(), - Encoding(encodingId, schema = encodingSchema), - SampleKind.fromInt(kind), - timestamp, - QoS(CongestionControl.fromInt(congestionControl), Priority.fromInt(priority), express), - attachmentBytes?.into() - ) - reply = Reply.Success(replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, sample) - } else { - reply = Reply.Error( - replierZid?.let { EntityGlobalId(ZenohId(it), replierEid.toUInt()) }, - payload1.into(), - Encoding(encodingId, schema = encodingSchema) - ) - } - handler.handle(reply) - } - - val selector = intoSelector.into() - getViaJNI( - selector.keyExpr.jniKeyExpr?.ptr ?: 0, - selector.keyExpr.keyExpr, - selector.parameters?.toString(), - sessionPtr, - getCallback, - handler::onClose, - options.timeout.toMillis(), - options.target.ordinal, - options.consolidation.ordinal, - options.attachment?.into()?.bytes, - options.payload?.into()?.bytes, - options.encoding?.id ?: Encoding.defaultEncoding().id, - options.encoding?.schema, - options.qos.congestionControl.value, - options.qos.priority.value, - options.qos.express, - options.acceptReplies.ordinal - ) - return handler.receiver() - } - - @Throws(ZError::class) - fun declareKeyExpr(keyExpr: String): KeyExpr { - val ptr = declareKeyExprViaJNI(sessionPtr, keyExpr) - return KeyExpr(keyExpr, JNIKeyExpr(ptr)) - } - - @Throws(ZError::class) - fun undeclareKeyExpr(keyExpr: KeyExpr) { - keyExpr.jniKeyExpr?.run { - undeclareKeyExprViaJNI(sessionPtr, this.ptr) - keyExpr.jniKeyExpr = null - } ?: throw ZError("Attempting to undeclare a non declared key expression.") - } - - @Throws(ZError::class) - fun performPut( - keyExpr: KeyExpr, - payload: IntoZBytes, - options: PutOptions, - ) { - val encoding = options.encoding ?: Encoding.defaultEncoding() - putViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - sessionPtr, - payload.into().bytes, - encoding.id, - encoding.schema, - options.congestionControl.value, - options.priority.value, - options.express, - options.attachment?.into()?.bytes, - options.reliability.ordinal - ) - } - - @Throws(ZError::class) - fun performDelete( - keyExpr: KeyExpr, - options: DeleteOptions, - ) { - deleteViaJNI( - keyExpr.jniKeyExpr?.ptr ?: 0, - keyExpr.keyExpr, - sessionPtr, - options.congestionControl.value, - options.priority.value, - options.express, - options.attachment?.into()?.bytes, - options.reliability.ordinal - ) - } - - @Throws(ZError::class) - fun zid(): ZenohId { - return ZenohId(getZidViaJNI(sessionPtr)) - } - - @Throws(ZError::class) - fun peersZid(): List { - return getPeersZidViaJNI(sessionPtr).map { ZenohId(it) } - } - - @Throws(ZError::class) - fun routersZid(): List { - return getRoutersZidViaJNI(sessionPtr).map { ZenohId(it) } - } - - @Throws(ZError::class) - private external fun getZidViaJNI(ptr: Long): ByteArray - - @Throws(ZError::class) - private external fun getPeersZidViaJNI(ptr: Long): List - - @Throws(ZError::class) - private external fun getRoutersZidViaJNI(ptr: Long): List - - @Throws(ZError::class) - private external fun closeSessionViaJNI(ptr: Long) - - @Throws(ZError::class) - private external fun declarePublisherViaJNI( - keyExprPtr: Long, - keyExprString: String, - sessionPtr: Long, - congestionControl: Int, - priority: Int, - express: Boolean, - reliability: Int - ): Long - - @Throws(ZError::class) - private external fun declareSubscriberViaJNI( - keyExprPtr: Long, - keyExprString: String, - sessionPtr: Long, - callback: JNISubscriberCallback, - onClose: JNIOnCloseCallback, - ): Long - - @Throws(ZError::class) - private external fun declareQueryableViaJNI( - keyExprPtr: Long, - keyExprString: String, - sessionPtr: Long, - callback: JNIQueryableCallback, - onClose: JNIOnCloseCallback, - complete: Boolean - ): Long - - @Throws(ZError::class) - private external fun declareQuerierViaJNI( - keyExprPtr: Long, - keyExprString: String, - sessionPtr: Long, - target: Int, - consolidation: Int, - congestionControl: Int, - priority: Int, - express: Boolean, - timeoutMs: Long, - acceptReplies: Int - ): Long - - @Throws(ZError::class) - private external fun declareKeyExprViaJNI(sessionPtr: Long, keyExpr: String): Long - - @Throws(ZError::class) - private external fun undeclareKeyExprViaJNI(sessionPtr: Long, keyExprPtr: Long) - - @Throws(ZError::class) - private external fun getViaJNI( - keyExprPtr: Long, - keyExprString: String, - selectorParams: String?, - sessionPtr: Long, - callback: JNIGetCallback, - onClose: JNIOnCloseCallback, - timeoutMs: Long, - target: Int, - consolidation: Int, - attachmentBytes: ByteArray?, - payload: ByteArray?, - encodingId: Int, - encodingSchema: String?, - congestionControl: Int, - priority: Int, - express: Boolean, - acceptReplies: Int, - ) - - @Throws(ZError::class) - private external fun putViaJNI( - keyExprPtr: Long, - keyExprString: String, - sessionPtr: Long, - valuePayload: ByteArray, - valueEncoding: Int, - valueEncodingSchema: String?, - congestionControl: Int, - priority: Int, - express: Boolean, - attachmentBytes: ByteArray?, - reliability: Int - ) - - @Throws(ZError::class) - private external fun deleteViaJNI( - keyExprPtr: Long, - keyExprString: String, - sessionPtr: Long, - congestionControl: Int, - priority: Int, - express: Boolean, - attachmentBytes: ByteArray?, - reliability: Int - ) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt deleted file mode 100644 index 1bb80543..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNISubscriber.kt +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -/** - * Adapter class to handle the interactions with Zenoh through JNI for a [io.zenoh.pubsub.Subscriber] - * - * @property ptr: raw pointer to the underlying native Subscriber. - */ -internal class JNISubscriber(private val ptr: Long) { - - fun close() { - freePtrViaJNI(ptr) - } - - /** Frees the underlying native Subscriber. */ - private external fun freePtrViaJNI(ptr: Long) - -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt deleted file mode 100644 index 53ecb5dc..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/JNIZenohId.kt +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni - -import io.zenoh.ZenohLoad - -internal object JNIZenohId { - - init { - ZenohLoad - } - - external fun toStringViaJNI(bytes: ByteArray): String - -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt deleted file mode 100644 index 14f3c8e9..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIGetCallback.kt +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni.callbacks - -internal fun interface JNIGetCallback { - - fun run( - replierZid: ByteArray?, - replierEid: Int, - success: Boolean, - keyExpr: String?, - payload: ByteArray, - encodingId: Int, - encodingSchema: String?, - kind: Int, - timestampNTP64: Long, - timestampIsValid: Boolean, - attachment: ByteArray?, - express: Boolean, - priority: Int, - congestionControl: Int, - ) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIOnCloseCallback.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIOnCloseCallback.kt deleted file mode 100644 index b58fa23d..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIOnCloseCallback.kt +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni.callbacks - -internal fun interface JNIOnCloseCallback { - - fun run() - -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt deleted file mode 100644 index addf1430..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIQueryableCallback.kt +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni.callbacks - -internal fun interface JNIQueryableCallback { - fun run(keyExpr: String, - selectorParams: String, - payload: ByteArray?, - encodingId: Int, - encodingSchema: String?, - attachmentBytes: ByteArray?, - queryPtr: Long, - acceptReplies: Int) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt deleted file mode 100644 index 0a8b20e9..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNIScoutCallback.kt +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni.callbacks - -internal fun interface JNIScoutCallback { - - fun run(whatAmI: Int, zid: ByteArray, locators: List) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISubscriberCallback.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISubscriberCallback.kt deleted file mode 100644 index 76373c72..00000000 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/jni/callbacks/JNISubscriberCallback.kt +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -package io.zenoh.jni.callbacks - -internal fun interface JNISubscriberCallback { - fun run( - keyExpr: String, - payload: ByteArray, - encodingId: Int, - encodingSchema: String?, - kind: Int, - timestampNTP64: Long, - timestampIsValid: Boolean, - attachment: ByteArray?, - express: Boolean, - priority: Int, - congestionControl: Int, - ) -} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt index b5fe6110..e45e12ac 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt @@ -15,11 +15,14 @@ package io.zenoh.keyexpr import io.zenoh.Session +import io.zenoh.ZenohLoad import io.zenoh.session.SessionDeclaration import io.zenoh.exceptions.ZError -import io.zenoh.jni.JNIKeyExpr +import io.zenoh.exceptions.wrapJNIExceptionAsZError +import io.zenoh.jni.keyexpr.ZKeyExpr import io.zenoh.query.IntoSelector import io.zenoh.query.Selector +import io.zenoh.jni.keyexpr.KeyExpr as JniKeyExpr /** * # Address space @@ -59,10 +62,39 @@ import io.zenoh.query.Selector * ensures that [close] is automatically called, safely managing the lifecycle of the [KeyExpr] instance. * */ -class KeyExpr internal constructor(internal val keyExpr: String, internal var jniKeyExpr: JNIKeyExpr? = null): AutoCloseable, IntoSelector, - SessionDeclaration { +class KeyExpr private constructor( + private val eagerFlat: JniKeyExpr?, + private val leafString: String?, + private val leafPtr: Long, +) : AutoCloseable, IntoSelector, SessionDeclaration { + + /** Eager path: an already-built [JniKeyExpr] (tryFrom / autocanonize / declareKeyExpr). */ + internal constructor(flat: JniKeyExpr) : this(flat, null, 0L) + + /** + * Lazy leaf path (hot inbound callback): keep only the leaf wires; the + * [JniKeyExpr] is built on first `.flat` access (native ops only). An + * inbound-only key expression — received in a [io.zenoh.sample.Sample] the + * consumer never sends back — never allocates a `JniKeyExpr`, matching the + * string + lazy-native model and avoiding per-message allocation/GC. + */ + internal constructor(keyExpr: String, ptr: Long = 0L) : this(null, keyExpr, ptr) + + /** The native-facing flat form; builds the [JniKeyExpr] lazily for the leaf path. */ + internal val flat: JniKeyExpr + get() = eagerFlat ?: lazyFlat + private val lazyFlat: JniKeyExpr by lazy { + JniKeyExpr(leafString!!, leafPtr.takeIf { it != 0L }?.let { ZKeyExpr(it) }) + } + + /** String form — read without forcing the lazy [JniKeyExpr] build. */ + private val keyExprString: String + get() = eagerFlat?.keyExprString ?: leafString!! companion object { + init { + ZenohLoad + } /** * Try from. @@ -78,8 +110,8 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn */ @JvmStatic @Throws(ZError::class) - fun tryFrom(keyExpr: String): KeyExpr { - return JNIKeyExpr.tryFrom(keyExpr) + fun tryFrom(keyExpr: String): KeyExpr = wrapJNIExceptionAsZError { + KeyExpr(JniKeyExpr.keyexprTryFrom(keyExpr)) } /** @@ -94,8 +126,8 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn */ @JvmStatic @Throws(ZError::class) - fun autocanonize(keyExpr: String): KeyExpr { - return JNIKeyExpr.autocanonize(keyExpr) + fun autocanonize(keyExpr: String): KeyExpr = wrapJNIExceptionAsZError { + KeyExpr(JniKeyExpr.keyexprAutocanonize(keyExpr)) } } @@ -105,8 +137,8 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn * Will return false as well if the key expression is not valid anymore. */ @Throws(ZError::class) - fun intersects(other: KeyExpr): Boolean { - return JNIKeyExpr.intersects(this, other) + fun intersects(other: KeyExpr): Boolean = wrapJNIExceptionAsZError { + JniKeyExpr.keyexprIntersects(this.flat, other.flat) } /** @@ -115,8 +147,8 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn * Will return false as well if the key expression is not valid anymore. */ @Throws(ZError::class) - fun includes(other: KeyExpr): Boolean { - return JNIKeyExpr.includes(this, other) + fun includes(other: KeyExpr): Boolean = wrapJNIExceptionAsZError { + JniKeyExpr.keyexprIncludes(this.flat, other.flat) } /** @@ -125,8 +157,8 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn * so you should favor these methods for most applications. */ @Throws(ZError::class) - fun relationTo(other: KeyExpr): SetIntersectionLevel { - return JNIKeyExpr.relationTo(this, other) + fun relationTo(other: KeyExpr): SetIntersectionLevel = wrapJNIExceptionAsZError { + SetIntersectionLevel.fromJni(JniKeyExpr.keyexprRelationTo(this.flat, other.flat)) } /** @@ -134,8 +166,8 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn * This should be your preferred method when concatenating path segments. */ @Throws(ZError::class) - fun join(other: String): KeyExpr { - return JNIKeyExpr.joinViaJNI(this, other) + fun join(other: String): KeyExpr = wrapJNIExceptionAsZError { + KeyExpr(JniKeyExpr.keyexprJoin(this.flat, other)) } /** @@ -143,13 +175,11 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn * You should probably prefer [join] as Zenoh may then take advantage of the hierarchical separation it inserts. */ @Throws(ZError::class) - fun concat(other: String): KeyExpr { - return JNIKeyExpr.concatViaJNI(this, other) + fun concat(other: String): KeyExpr = wrapJNIExceptionAsZError { + KeyExpr(JniKeyExpr.keyexprConcat(this.flat, other)) } - override fun toString(): String { - return keyExpr - } + override fun toString(): String = keyExprString /** * Equivalent to [undeclare]. This function is automatically called when using try with resources. @@ -166,8 +196,13 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn * operations on it, but without the inner optimizations. */ override fun undeclare() { - jniKeyExpr?.close() - jniKeyExpr = null + // Only free a native handle if one exists. An inbound string-only key + // expression (leaf path, no ptr) has nothing to close and must NOT + // force-build its lazy JniKeyExpr just to no-op. + when { + eagerFlat != null -> eagerFlat.close() + leafPtr != 0L -> flat.close() + } } override fun into(): Selector = Selector(this) @@ -178,10 +213,10 @@ class KeyExpr internal constructor(internal val keyExpr: String, internal var jn other as KeyExpr - return keyExpr == other.keyExpr + return keyExprString == other.keyExprString } override fun hashCode(): Int { - return keyExpr.hashCode() + return keyExprString.hashCode() } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/SetIntersectionLevel.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/SetIntersectionLevel.kt index 981cc4b1..56c7e3ed 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/SetIntersectionLevel.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/SetIntersectionLevel.kt @@ -19,13 +19,14 @@ package io.zenoh.keyexpr * * Note that [EQUALS] implies [INCLUDES], which itself implies [INTERSECTS]. */ -enum class SetIntersectionLevel(internal val value: Int) { - DISJOINT(0), - INTERSECTS(1), - INCLUDES(2), - EQUALS(3); +enum class SetIntersectionLevel(internal val jni: io.zenoh.jni.keyexpr.SetIntersectionLevel) { + DISJOINT(io.zenoh.jni.keyexpr.SetIntersectionLevel.DISJOINT), + INTERSECTS(io.zenoh.jni.keyexpr.SetIntersectionLevel.INTERSECTS), + INCLUDES(io.zenoh.jni.keyexpr.SetIntersectionLevel.INCLUDES), + EQUALS(io.zenoh.jni.keyexpr.SetIntersectionLevel.EQUALS); companion object { - internal fun fromInt(value: Int) = SetIntersectionLevel.entries.first { it.value == value } + internal fun fromJni(jni: io.zenoh.jni.keyexpr.SetIntersectionLevel): SetIntersectionLevel = + entries.first { it.jni == jni } } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt index 96711557..85229326 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt @@ -15,11 +15,12 @@ package io.zenoh.liveliness import io.zenoh.Session +import io.zenoh.replyCallbackOf +import io.zenoh.sampleCallbackOf import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback import io.zenoh.handlers.Handler -import io.zenoh.jni.JNILiveliness import io.zenoh.keyexpr.KeyExpr import io.zenoh.pubsub.CallbackSubscriber import io.zenoh.pubsub.HandlerSubscriber @@ -48,8 +49,8 @@ class Liveliness internal constructor(private val session: Session) { */ @Throws(ZError::class) fun declareToken(keyExpr: KeyExpr): LivelinessToken { - val jniSession = session.jniSession ?: throw Session.sessionClosedException - return JNILiveliness.declareToken(jniSession, keyExpr) + val zSession = session.zSession ?: throw Session.sessionClosedException + return LivelinessToken(zSession.livelinessDeclareToken(keyExpr.flat)) } /** @@ -64,16 +65,15 @@ class Liveliness internal constructor(private val session: Session) { keyExpr: KeyExpr, timeout: Duration = Duration.ofMillis(10000), ): BlockingQueue> { - val jniSession = session.jniSession ?: throw Session.sessionClosedException + val zSession = session.zSession ?: throw Session.sessionClosedException val handler = BlockingQueueHandler(LinkedBlockingDeque()) - return JNILiveliness.get( - jniSession, - keyExpr, - handler::handle, - receiver = handler.receiver(), - timeout, - onClose = handler::onClose + zSession.livelinessGet( + keyExpr.flat, + timeout.toMillis(), + replyCallbackOf { handler.handle(it) }, + io.zenoh.jni.callbacks.Callback { handler.onClose() } ) + return handler.receiver() } /** @@ -88,8 +88,13 @@ class Liveliness internal constructor(private val session: Session) { fun get( keyExpr: KeyExpr, callback: Callback, timeout: Duration = Duration.ofMillis(10000) ) { - val jniSession = session.jniSession ?: throw Session.sessionClosedException - return JNILiveliness.get(jniSession, keyExpr, callback, Unit, timeout, {}) + val zSession = session.zSession ?: throw Session.sessionClosedException + zSession.livelinessGet( + keyExpr.flat, + timeout.toMillis(), + replyCallbackOf { callback.run(it) }, + io.zenoh.jni.callbacks.Callback { } + ) } /** @@ -105,16 +110,14 @@ class Liveliness internal constructor(private val session: Session) { fun get( keyExpr: KeyExpr, handler: Handler, timeout: Duration = Duration.ofMillis(10000) ): R { - val jniSession = session.jniSession ?: throw Session.sessionClosedException - val callback = handler::handle - return JNILiveliness.get( - jniSession, - keyExpr, - callback, - handler.receiver(), - timeout, - onClose = handler::onClose + val zSession = session.zSession ?: throw Session.sessionClosedException + zSession.livelinessGet( + keyExpr.flat, + timeout.toMillis(), + replyCallbackOf { handler.handle(it) }, + io.zenoh.jni.callbacks.Callback { handler.onClose() } ) + return handler.receiver() } /** @@ -130,15 +133,14 @@ class Liveliness internal constructor(private val session: Session) { options: LivelinessSubscriberOptions = LivelinessSubscriberOptions() ): HandlerSubscriber>> { val handler = BlockingQueueHandler(LinkedBlockingDeque()) - val jniSession = session.jniSession ?: throw Session.sessionClosedException - return JNILiveliness.declareSubscriber( - jniSession, - keyExpr, - handler::handle, - handler.receiver(), + val zSession = session.zSession ?: throw Session.sessionClosedException + val zSubscriber = zSession.livelinessDeclareSubscriber( + keyExpr.flat, options.history, - handler::onClose + sampleCallbackOf { handler.handle(it) }, + io.zenoh.jni.callbacks.Callback { handler.onClose() } ) + return HandlerSubscriber(keyExpr, zSubscriber, handler.receiver()) } /** @@ -155,14 +157,14 @@ class Liveliness internal constructor(private val session: Session) { callback: Callback, options: LivelinessSubscriberOptions = LivelinessSubscriberOptions() ): CallbackSubscriber { - val jniSession = session.jniSession ?: throw Session.sessionClosedException - return JNILiveliness.declareSubscriber( - jniSession, - keyExpr, - callback, + val zSession = session.zSession ?: throw Session.sessionClosedException + val zSubscriber = zSession.livelinessDeclareSubscriber( + keyExpr.flat, options.history, - fun() {} + sampleCallbackOf { callback.run(it) }, + io.zenoh.jni.callbacks.Callback { } ) + return CallbackSubscriber(keyExpr, zSubscriber) } /** @@ -180,15 +182,14 @@ class Liveliness internal constructor(private val session: Session) { handler: Handler, options: LivelinessSubscriberOptions = LivelinessSubscriberOptions() ): HandlerSubscriber { - val jniSession = session.jniSession ?: throw Session.sessionClosedException - return JNILiveliness.declareSubscriber( - jniSession, - keyExpr, - handler::handle, - handler.receiver(), + val zSession = session.zSession ?: throw Session.sessionClosedException + val zSubscriber = zSession.livelinessDeclareSubscriber( + keyExpr.flat, options.history, - handler::onClose + sampleCallbackOf { handler.handle(it) }, + io.zenoh.jni.callbacks.Callback { handler.onClose() } ) + return HandlerSubscriber(keyExpr, zSubscriber, handler.receiver()) } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt index 5d95b8fa..b4509d7d 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/LivelinessToken.kt @@ -14,7 +14,7 @@ package io.zenoh.liveliness -import io.zenoh.jni.JNILivelinessToken +import io.zenoh.jni.liveliness.ZLivelinessToken import io.zenoh.session.SessionDeclaration /** @@ -29,14 +29,14 @@ import io.zenoh.session.SessionDeclaration * * Liveliness tokens are automatically undeclared when dropped. */ -class LivelinessToken internal constructor(private var jniLivelinessToken: JNILivelinessToken?): SessionDeclaration, AutoCloseable { +class LivelinessToken internal constructor(private var token: ZLivelinessToken?): SessionDeclaration, AutoCloseable { /** * Undeclares the token. */ override fun undeclare() { - jniLivelinessToken?.undeclare() - jniLivelinessToken = null + token?.close() + token = null } /** diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index d0a9de2e..0c68c068 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -19,7 +19,8 @@ import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes import io.zenoh.exceptions.ZError -import io.zenoh.jni.JNIPublisher +import io.zenoh.exceptions.wrapJNIExceptionAsZError +import io.zenoh.jni.pubsub.ZPublisher import io.zenoh.keyexpr.KeyExpr import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority @@ -63,7 +64,7 @@ class Publisher internal constructor( private var congestionControl: CongestionControl, private var priority: Priority, val encoding: Encoding, - private var jniPublisher: JNIPublisher?, + private var zPublisher: ZPublisher?, ) : SessionDeclaration, AutoCloseable { companion object { @@ -79,13 +80,13 @@ class Publisher internal constructor( /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ @Throws(ZError::class) fun put(payload: IntoZBytes) { - jniPublisher?.put(payload, encoding, null) ?: throw publisherNotValid + performPut(payload, encoding, null) } /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ @Throws(ZError::class) fun put(payload: IntoZBytes, options: PutOptions) { - jniPublisher?.put(payload, options.encoding ?: this.encoding, options.attachment) ?: throw publisherNotValid + performPut(payload, options.encoding ?: this.encoding, options.attachment) } /** Performs a PUT operation on the specified [keyExpr] with the specified [payload]. */ @@ -102,14 +103,17 @@ class Publisher internal constructor( @JvmOverloads @Throws(ZError::class) fun delete(options: DeleteOptions = DeleteOptions()) { - jniPublisher?.delete(options.attachment) ?: throw(publisherNotValid) + val p = zPublisher ?: throw publisherNotValid + wrapJNIExceptionAsZError { + p.publisherDelete(options.attachment?.into()?.inner) + } } /** * Returns `true` if the publisher is still running. */ fun isValid(): Boolean { - return jniPublisher != null + return zPublisher != null } override fun close() { @@ -117,12 +121,24 @@ class Publisher internal constructor( } override fun undeclare() { - jniPublisher?.close() - jniPublisher = null + zPublisher?.close() + zPublisher = null } @Suppress("removal") protected fun finalize() { - jniPublisher?.close() + zPublisher?.close() + } + + @Throws(ZError::class) + private fun performPut(payload: IntoZBytes, encoding: Encoding, attachment: IntoZBytes?) { + val p = zPublisher ?: throw publisherNotValid + wrapJNIExceptionAsZError { + p.publisherPut( + payload.into().inner, + encoding.toFlat(), + attachment?.into()?.inner, + ) + } } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt index a3688303..62eb44d4 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Subscriber.kt @@ -15,7 +15,7 @@ package io.zenoh.pubsub import io.zenoh.handlers.BlockingQueueHandler -import io.zenoh.jni.JNISubscriber +import io.zenoh.jni.pubsub.ZSubscriber import io.zenoh.keyexpr.KeyExpr import io.zenoh.session.SessionDeclaration @@ -63,16 +63,16 @@ import io.zenoh.session.SessionDeclaration * ``` */ sealed class Subscriber( - val keyExpr: KeyExpr, private var jniSubscriber: JNISubscriber? + val keyExpr: KeyExpr, private var zSubscriber: ZSubscriber? ) : AutoCloseable, SessionDeclaration { fun isValid(): Boolean { - return jniSubscriber != null + return zSubscriber != null } override fun undeclare() { - jniSubscriber?.close() - jniSubscriber = null + zSubscriber?.close() + zSubscriber = null } override fun close() { @@ -80,7 +80,7 @@ sealed class Subscriber( } protected fun finalize() { - jniSubscriber?.close() + zSubscriber?.close() } } @@ -94,7 +94,7 @@ sealed class Subscriber( * } * ``` */ -class CallbackSubscriber internal constructor(keyExpr: KeyExpr, jniSubscriber: JNISubscriber?): Subscriber(keyExpr, jniSubscriber) +class CallbackSubscriber internal constructor(keyExpr: KeyExpr, zSubscriber: ZSubscriber?): Subscriber(keyExpr, zSubscriber) /** * Subscriber using a [io.zenoh.handlers.Handler] for handling incoming samples. @@ -119,4 +119,4 @@ class CallbackSubscriber internal constructor(keyExpr: KeyExpr, jniSubscriber: J * @param R The type of the receiver. * @param receiver The receiver of the subscriber's handler. */ -class HandlerSubscriber internal constructor(keyExpr: KeyExpr, jniSubscriber: JNISubscriber?, val receiver: R): Subscriber(keyExpr, jniSubscriber) +class HandlerSubscriber internal constructor(keyExpr: KeyExpr, zSubscriber: ZSubscriber?, val receiver: R): Subscriber(keyExpr, zSubscriber) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt index 82b3463a..4a45f8cb 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/CongestionControl.kt @@ -15,20 +15,30 @@ package io.zenoh.qos /** The congestion control to be applied when routing the data. */ -enum class CongestionControl (val value: Int) { +enum class CongestionControl (internal val jni: io.zenoh.jni.qos.CongestionControl) { /** * Allows the message to be dropped if all buffers are full. */ - DROP(0), + DROP(io.zenoh.jni.qos.CongestionControl.DROP), /** * Prevents the message from being dropped at all cost. * In the face of heavy congestion on a part of the network, this could result in your publisher node blocking. */ - BLOCK(1); + BLOCK(io.zenoh.jni.qos.CongestionControl.BLOCK), + + /** + * Blocks low-priority traffic first, then drops when needed. + */ + BLOCK_FIRST(io.zenoh.jni.qos.CongestionControl.BLOCK_FIRST); + + val value: Int + get() = jni.value companion object { fun fromInt(value: Int) = entries.first { it.value == value } + + internal fun fromJni(jni: io.zenoh.jni.qos.CongestionControl): CongestionControl = fromInt(jni.value) } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt index 0e27780e..4ba4c7e7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Priority.kt @@ -22,16 +22,21 @@ package io.zenoh.qos * - Highest priority: 1 ([REALTIME]) * - Lowest priority: 7 ([BACKGROUND]) */ -enum class Priority(val value: Int) { - REALTIME(1), - INTERACTIVE_HIGH(2), - INTERACTIVE_LOW(3), - DATA_HIGH(4), - DATA(5), - DATA_LOW(6), - BACKGROUND(7); +enum class Priority(internal val jni: io.zenoh.jni.qos.Priority) { + REALTIME(io.zenoh.jni.qos.Priority.REAL_TIME), + INTERACTIVE_HIGH(io.zenoh.jni.qos.Priority.INTERACTIVE_HIGH), + INTERACTIVE_LOW(io.zenoh.jni.qos.Priority.INTERACTIVE_LOW), + DATA_HIGH(io.zenoh.jni.qos.Priority.DATA_HIGH), + DATA(io.zenoh.jni.qos.Priority.DATA), + DATA_LOW(io.zenoh.jni.qos.Priority.DATA_LOW), + BACKGROUND(io.zenoh.jni.qos.Priority.BACKGROUND); + + val value: Int + get() = jni.value companion object { fun fromInt(value: Int) = entries.first { it.value == value } + + internal fun fromJni(jni: io.zenoh.jni.qos.Priority): Priority = fromInt(jni.value) } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Reliability.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Reliability.kt index d574f27c..fe009d62 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Reliability.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/qos/Reliability.kt @@ -36,4 +36,17 @@ enum class Reliability { * this reliability requirement may be infringed to prevent slow readers from blocking the network. */ RELIABLE, + + ; + + internal val jni: io.zenoh.jni.qos.Reliability + get() = when (this) { + BEST_EFFORT -> io.zenoh.jni.qos.Reliability.BEST_EFFORT + RELIABLE -> io.zenoh.jni.qos.Reliability.RELIABLE + } + + companion object { + internal fun fromJni(jni: io.zenoh.jni.qos.Reliability): Reliability = + entries.first { it.jni == jni } + } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ConsolidationMode.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ConsolidationMode.kt index f4c1b29c..7a0797d7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ConsolidationMode.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ConsolidationMode.kt @@ -36,3 +36,10 @@ enum class ConsolidationMode { /** Holds back samples to only send the set of samples that had the highest timestamp for their key. */ LATEST; } + +internal fun ConsolidationMode.toFlat(): io.zenoh.jni.query.ConsolidationMode = when (this) { + ConsolidationMode.AUTO -> io.zenoh.jni.query.ConsolidationMode.AUTO + ConsolidationMode.NONE -> io.zenoh.jni.query.ConsolidationMode.NONE + ConsolidationMode.MONOTONIC -> io.zenoh.jni.query.ConsolidationMode.MONOTONIC + ConsolidationMode.LATEST -> io.zenoh.jni.query.ConsolidationMode.LATEST +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt index 541d056b..c8e5651b 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt @@ -15,6 +15,7 @@ package io.zenoh.query import io.zenoh.annotations.Unstable +import io.zenoh.replyCallbackOf import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes @@ -22,7 +23,7 @@ import io.zenoh.exceptions.ZError import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback import io.zenoh.handlers.Handler -import io.zenoh.jni.JNIQuerier +import io.zenoh.jni.query.ZQuerier import io.zenoh.keyexpr.KeyExpr import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority @@ -54,7 +55,7 @@ import java.util.concurrent.LinkedBlockingDeque * @param keyExpr The [KeyExpr] of the querier. * @param qos The [QoS] configuration of the querier. */ -class Querier internal constructor(val keyExpr: KeyExpr, val qos: QoS, private var jniQuerier: JNIQuerier?) : +class Querier internal constructor(val keyExpr: KeyExpr, val qos: QoS, private var zQuerier: ZQuerier?) : SessionDeclaration, AutoCloseable { /** @@ -78,7 +79,7 @@ class Querier internal constructor(val keyExpr: KeyExpr, val qos: QoS, private v options: GetOptions ): BlockingQueue> { val handler = BlockingQueueHandler(LinkedBlockingDeque()) - return resolveGetWithHandler(keyExpr, handler, options) + return resolveGetWithHandler(handler, options) } /** @@ -93,7 +94,7 @@ class Querier internal constructor(val keyExpr: KeyExpr, val qos: QoS, private v callback: Callback, options: GetOptions ) { - resolveGetWithCallback(keyExpr, callback, options) + resolveGetWithCallback(callback, options) } /** @@ -108,7 +109,7 @@ class Querier internal constructor(val keyExpr: KeyExpr, val qos: QoS, private v handler: Handler, options: GetOptions ): R { - return resolveGetWithHandler(keyExpr, handler, options) + return resolveGetWithHandler(handler, options) } /** @@ -126,8 +127,8 @@ class Querier internal constructor(val keyExpr: KeyExpr, val qos: QoS, private v * performed on it will fail. */ override fun undeclare() { - jniQuerier?.close() - jniQuerier = null + zQuerier?.close() + zQuerier = null } /** @@ -142,12 +143,29 @@ class Querier internal constructor(val keyExpr: KeyExpr, val qos: QoS, private v undeclare() } - private fun resolveGetWithCallback(keyExpr: KeyExpr, callback: Callback, options: GetOptions) { - jniQuerier?.performGetWithCallback(keyExpr, callback, options) ?: throw ZError("Querier is not valid.") + private fun resolveGetWithCallback(callback: Callback, options: GetOptions) { + val q = zQuerier ?: throw ZError("Querier is not valid.") + q.querierGet( + options.parameters?.toString(), + options.payload?.into()?.inner, + (options.encoding ?: Encoding.defaultEncoding()).toFlat(), + options.attachment?.into()?.inner, + replyCallbackOf { callback.run(it) }, + io.zenoh.jni.callbacks.Callback { } + ) } - private fun resolveGetWithHandler(keyExpr: KeyExpr, handler: Handler, options: GetOptions): R { - return jniQuerier?.performGetWithHandler(keyExpr, handler, options) ?: throw ZError("Querier is not valid.") + private fun resolveGetWithHandler(handler: Handler, options: GetOptions): R { + val q = zQuerier ?: throw ZError("Querier is not valid.") + q.querierGet( + options.parameters?.toString(), + options.payload?.into()?.inner, + (options.encoding ?: Encoding.defaultEncoding()).toFlat(), + options.attachment?.into()?.inner, + replyCallbackOf { handler.handle(it) }, + io.zenoh.jni.callbacks.Callback { handler.onClose() } + ) + return handler.receiver() } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index 3a8184da..62284404 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -19,11 +19,8 @@ import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes import io.zenoh.exceptions.ZError -import io.zenoh.jni.JNIQuery +import io.zenoh.jni.query.ZQuery import io.zenoh.keyexpr.KeyExpr -import io.zenoh.qos.QoS -import io.zenoh.sample.Sample -import io.zenoh.sample.SampleKind /** * Represents a Zenoh Query in Kotlin. @@ -44,12 +41,60 @@ class Query internal constructor( val encoding: Encoding?, val attachment: ZBytes?, val acceptsReplies: ReplyKeyExpr, - private var jniQuery: JNIQuery? + private var zQuery: ZQuery? ) : AutoCloseable, ZenohType { /** Shortcut to the [selector]'s parameters. */ val parameters = selector.parameters + internal companion object { + /** Repacks the flat [io.zenoh.jni.query.Query] data class delivered by a queryable callback. */ + fun from(flat: io.zenoh.jni.query.Query): Query { + val ke = KeyExpr(flat.keyExpr) + val selector = if (flat.parameters.isEmpty()) Selector(ke) + else Selector(ke, Parameters.from(flat.parameters)) + return Query( + ke, + selector, + flat.payload?.let { ZBytes(it) }, + flat.encoding?.let { Encoding(it) }, + flat.attachment?.let { ZBytes(it) }, + flat.acceptsReplies.toPublic(), + flat.query + ) + } + + /** + * Builds a [Query] **directly** from the flattened leaf wires the JNI callback + * delivers — no intermediate `jni.Query`/`jni.Encoding` objects. + */ + fun fromFlat( + keyExprString: String, + keyExprNative: Long, + parameters: String, + payload: ByteArray?, + encodingPresent: Boolean, + encodingId: Int, + encodingSchema: String?, + attachment: ByteArray?, + acceptsReplies: Int, + query: Long, + ): Query { + val ke = KeyExpr(keyExprString, keyExprNative) + val selector = if (parameters.isEmpty()) Selector(ke) + else Selector(ke, Parameters.from(parameters)) + return Query( + ke, + selector, + payload?.let { ZBytes.from(it) }, + if (encodingPresent) Encoding(encodingId, encodingSchema) else null, + attachment?.let { ZBytes.from(it) }, + io.zenoh.jni.query.ReplyKeyExpr.fromInt(acceptsReplies).toPublic(), + ZQuery(query) + ) + } + } + /** * Reply to the specified key expression. * @@ -61,19 +106,16 @@ class Query internal constructor( @Throws(ZError::class) @JvmOverloads fun reply(keyExpr: KeyExpr, payload: IntoZBytes, options: ReplyOptions = ReplyOptions()) { - val sample = Sample( - keyExpr, - payload.into(), - options.encoding, - SampleKind.PUT, - options.timeStamp, - QoS(options.congestionControl, options.priority, options.express), - options.attachment?.into() + val q = zQuery ?: throw ZError("Query is invalid") + q.queryReplySuccess( + keyExpr.flat, + payload.into().inner, + options.encoding.toFlat(), + options.timeStamp?.ntpValue(), + options.attachment?.into()?.inner, + options.express ) - jniQuery?.apply { - replySuccess(sample) - jniQuery = null - } ?: throw (ZError("Query is invalid")) + zQuery = null } /** @@ -98,15 +140,14 @@ class Query internal constructor( @JvmOverloads @Throws(ZError::class) fun replyDel(keyExpr: KeyExpr, options: ReplyDelOptions = ReplyDelOptions()) { - jniQuery?.apply { - replyDelete( - keyExpr, - options.timeStamp, - options.attachment, - QoS(options.congestionControl, options.priority, options.express), - ) - jniQuery = null - } ?: throw (ZError("Query is invalid")) + val q = zQuery ?: throw ZError("Query is invalid") + q.queryReplyDelete( + keyExpr.flat, + options.timeStamp?.ntpValue(), + options.attachment?.into()?.inner, + options.express + ) + zQuery = null } /** @@ -118,10 +159,9 @@ class Query internal constructor( @JvmOverloads @Throws(ZError::class) fun replyErr(message: IntoZBytes, options: ReplyErrOptions = ReplyErrOptions()) { - jniQuery?.apply { - replyError(message.into(), options.encoding) - jniQuery = null - } ?: throw (ZError("Query is invalid")) + val q = zQuery ?: throw ZError("Query is invalid") + q.queryReplyError(message.into().inner, options.encoding.toFlat()) + zQuery = null } /** @@ -135,10 +175,8 @@ class Query internal constructor( fun replyErr(message: String, options: ReplyErrOptions = ReplyErrOptions()) = replyErr(ZBytes.from(message), options) override fun close() { - jniQuery?.apply { - this.close() - jniQuery = null - } + zQuery?.close() + zQuery = null } @Suppress("removal") diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/QueryTarget.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/QueryTarget.kt index 2711f6f6..9261c835 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/QueryTarget.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/QueryTarget.kt @@ -33,3 +33,9 @@ enum class QueryTarget { ALL_COMPLETE; } +internal fun QueryTarget.toFlat(): io.zenoh.jni.query.QueryTarget = when (this) { + QueryTarget.BEST_MATCHING -> io.zenoh.jni.query.QueryTarget.BEST_MATCHING + QueryTarget.ALL -> io.zenoh.jni.query.QueryTarget.ALL + QueryTarget.ALL_COMPLETE -> io.zenoh.jni.query.QueryTarget.ALL_COMPLETE +} + diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt index f8159cd9..ef51090a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Queryable.kt @@ -16,7 +16,7 @@ package io.zenoh.query import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Handler -import io.zenoh.jni.JNIQueryable +import io.zenoh.jni.query.ZQueryable import io.zenoh.keyexpr.KeyExpr import io.zenoh.session.SessionDeclaration @@ -55,19 +55,19 @@ import io.zenoh.session.SessionDeclaration * @see HandlerQueryable */ sealed class Queryable( - val keyExpr: KeyExpr, private var jniQueryable: JNIQueryable? + val keyExpr: KeyExpr, private var zQueryable: ZQueryable? ) : AutoCloseable, SessionDeclaration { fun isValid(): Boolean { - return jniQueryable != null + return zQueryable != null } /** * Undeclares the queryable. */ override fun undeclare() { - jniQueryable?.close() - jniQueryable = null + zQueryable?.close() + zQueryable = null } /** @@ -79,7 +79,7 @@ sealed class Queryable( } protected fun finalize() { - jniQueryable?.close() + zQueryable?.close() } } @@ -93,7 +93,7 @@ sealed class Queryable( * } * ``` */ -class CallbackQueryable internal constructor(keyExpr: KeyExpr, jniQueryable: JNIQueryable?): Queryable(keyExpr, jniQueryable) +class CallbackQueryable internal constructor(keyExpr: KeyExpr, zQueryable: ZQueryable?): Queryable(keyExpr, zQueryable) /** * [Queryable] receiving replies through a [Handler]. @@ -117,7 +117,7 @@ class CallbackQueryable internal constructor(keyExpr: KeyExpr, jniQueryable: JNI * @param R The type of the handler's receiver. * @param receiver The receiver of the queryable's handler. */ -class HandlerQueryable internal constructor(keyExpr: KeyExpr, jniQueryable: JNIQueryable?, val receiver: R): Queryable(keyExpr, jniQueryable) +class HandlerQueryable internal constructor(keyExpr: KeyExpr, zQueryable: ZQueryable?, val receiver: R): Queryable(keyExpr, zQueryable) /** * Options for configuring a [Queryable]. diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt index c69dc349..9c38f3d1 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Reply.kt @@ -19,6 +19,7 @@ import io.zenoh.bytes.Encoding import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes import io.zenoh.config.EntityGlobalId +import io.zenoh.config.ZenohId import io.zenoh.sample.Sample import io.zenoh.qos.CongestionControl import io.zenoh.qos.Priority @@ -34,6 +35,72 @@ import org.apache.commons.net.ntp.TimeStamp */ sealed class Reply private constructor(val replierId: EntityGlobalId?) : ZenohType { + internal companion object { + /** Repacks the flat [io.zenoh.jni.query.Reply] delivered by `querier_get`. */ + fun from(flat: io.zenoh.jni.query.Reply): Reply { + val replierId = flat.replierZid?.let { + EntityGlobalId(ZenohId(it), flat.replierEid.toUInt()) + } + val sample = flat.sample + return if (sample != null) { + Success(replierId, Sample.from(sample)) + } else { + Error(replierId, ZBytes(flat.errorPayload!!), Encoding(flat.errorEncoding!!)) + } + } + + /** + * Builds a [Reply] **directly** from the flattened leaf wires the JNI callback + * delivers — no intermediate `jni.Reply`/`jni.Sample` objects. The nested sample + * is reconstructed via [Sample.fromFlat] from its own (sample-prefixed) leaves. + */ + @Suppress("LongParameterList") + fun fromFlat( + replierZid: ByteArray?, + replierEid: Int, + samplePresent: Boolean, + sampleKeyExprString: String?, + sampleKeyExprNative: Long, + samplePayload: ByteArray?, + sampleEncodingId: Int, + sampleEncodingSchema: String?, + sampleKind: Int, + sampleTimestampPresent: Boolean, + sampleTimestampNtp64: Long, + sampleTimestampId: ByteArray?, + sampleExpress: Boolean, + samplePriority: Int, + sampleCongestionControl: Int, + sampleAttachment: ByteArray?, + errorPayload: ByteArray?, + errorEncodingPresent: Boolean, + errorEncodingId: Int, + errorEncodingSchema: String?, + ): Reply { + val replierId = replierZid?.let { + EntityGlobalId(ZenohId(io.zenoh.jni.config.ZenohId(it)), replierEid.toUInt()) + } + return if (samplePresent) { + Success( + replierId, + Sample.fromFlat( + sampleKeyExprString!!, sampleKeyExprNative, samplePayload!!, + sampleEncodingId, sampleEncodingSchema, sampleKind, sampleTimestampPresent, + sampleTimestampNtp64, sampleTimestampId, sampleExpress, samplePriority, + sampleCongestionControl, sampleAttachment + ) + ) + } else { + Error( + replierId, + ZBytes.from(errorPayload!!), + if (errorEncodingPresent) Encoding(errorEncodingId, errorEncodingSchema) + else Encoding(0, null) + ) + } + } + } + /** * A Success reply. */ diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyKeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyKeyExpr.kt index 08591819..2cc2dfc8 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyKeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/ReplyKeyExpr.kt @@ -32,3 +32,13 @@ enum class ReplyKeyExpr { */ ANY; } + +internal fun io.zenoh.jni.query.ReplyKeyExpr.toPublic(): ReplyKeyExpr = when (this) { + io.zenoh.jni.query.ReplyKeyExpr.ANY -> ReplyKeyExpr.ANY + io.zenoh.jni.query.ReplyKeyExpr.MATCHING_QUERY -> ReplyKeyExpr.MATCHING_QUERY +} + +internal fun ReplyKeyExpr.toFlat(): io.zenoh.jni.query.ReplyKeyExpr = when (this) { + ReplyKeyExpr.MATCHING_QUERY -> io.zenoh.jni.query.ReplyKeyExpr.MATCHING_QUERY + ReplyKeyExpr.ANY -> io.zenoh.jni.query.ReplyKeyExpr.ANY +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt index 216d67e0..0806ce35 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/Sample.kt @@ -16,6 +16,8 @@ package io.zenoh.sample import io.zenoh.ZenohType import io.zenoh.qos.QoS +import io.zenoh.qos.CongestionControl +import io.zenoh.qos.Priority import io.zenoh.keyexpr.KeyExpr import io.zenoh.bytes.Encoding import io.zenoh.bytes.ZBytes @@ -48,4 +50,55 @@ data class Sample( val express = qos.express val congestionControl = qos.congestionControl val priority = qos.priority + + internal companion object { + /** Repacks the flat [io.zenoh.jni.sample.Sample] decoded by zenoh-flat. */ + fun from(flat: io.zenoh.jni.sample.Sample): Sample = Sample( + KeyExpr(flat.keyExpr), + ZBytes(flat.payload), + Encoding(flat.encoding), + flat.kind.toPublic(), + flat.timestamp?.let { TimeStamp(it.ntp64) }, + QoS( + CongestionControl.fromJni(flat.congestionControl), + Priority.fromJni(flat.priority), + flat.express + ), + flat.attachment?.let { ZBytes(it) } + ) + + /** + * Builds a [Sample] from the flattened leaf wires the JNI callback now + * delivers (the native side makes one `run(...)` crossing instead of + * building a `jni.Sample` and round-tripping it). The graph is + * reassembled in JVM bytecode via the generated `fromParts` factory. + */ + fun fromFlat( + keyExprString: String, + keyExprNative: Long, + payload: ByteArray, + encodingId: Int, + encodingSchema: String?, + kind: Int, + timestampPresent: Boolean, + timestampNtp64: Long, + timestampId: ByteArray?, + express: Boolean, + priority: Int, + congestionControl: Int, + attachment: ByteArray?, + ): Sample = Sample( + KeyExpr(keyExprString, keyExprNative), + ZBytes.from(payload), + Encoding(encodingId, encodingSchema), + io.zenoh.jni.sample.SampleKind.fromInt(kind).toPublic(), + if (timestampPresent) TimeStamp(timestampNtp64) else null, + QoS( + CongestionControl.fromInt(congestionControl), + Priority.fromInt(priority), + express + ), + attachment?.let { ZBytes.from(it) } + ) + } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/SampleKind.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/SampleKind.kt index cea02a02..488450c6 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/SampleKind.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/sample/SampleKind.kt @@ -23,3 +23,8 @@ enum class SampleKind { fun fromInt(value: Int) = entries.first { it.ordinal == value } } } + +internal fun io.zenoh.jni.sample.SampleKind.toPublic(): SampleKind = when (this) { + io.zenoh.jni.sample.SampleKind.PUT -> SampleKind.PUT + io.zenoh.jni.sample.SampleKind.DELETE -> SampleKind.DELETE +} diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt index 8034a851..dc3f6fdf 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt @@ -14,7 +14,15 @@ package io.zenoh.scouting -import io.zenoh.jni.JNIScout +import io.zenoh.Config +import io.zenoh.ZenohLoad +import io.zenoh.config.WhatAmI +import io.zenoh.config.ZenohId +import io.zenoh.exceptions.ZError +import io.zenoh.exceptions.wrapJNIExceptionAsZError +import io.zenoh.handlers.Callback +import io.zenoh.jni.scouting.ZScout +import io.zenoh.jni.callbacks.HelloCallback /** * Scout for routers and/or peers. @@ -62,15 +70,54 @@ import io.zenoh.jni.JNIScout * @see HandlerScout */ sealed class Scout ( - private var jniScout: JNIScout? + private var zScout: ZScout? ) : AutoCloseable { + companion object { + + init { + ZenohLoad + } + + @Throws(ZError::class) + internal fun scoutWithHandler( + whatAmI: Set, + callback: Callback, + onClose: () -> Unit, + config: Config?, + receiver: R, + ): HandlerScout = wrapJNIExceptionAsZError { + HandlerScout(runScout(whatAmI, config, callback, onClose), receiver) + } + + @Throws(ZError::class) + internal fun scoutWithCallback( + whatAmI: Set, + callback: Callback, + config: Config?, + ): CallbackScout = wrapJNIExceptionAsZError { + CallbackScout(runScout(whatAmI, config, callback) {}) + } + + private fun runScout( + whatAmI: Set, + config: Config?, + callback: Callback, + onClose: () -> Unit, + ): ZScout { + val bitfield = whatAmI.map { it.jni.value }.reduce { acc, v -> acc or v } + val helloCallback = io.zenoh.helloCallbackOf { callback.run(it) } + val onCloseCallback = io.zenoh.jni.callbacks.Callback { onClose() } + return io.zenoh.jni.scouting.scout(bitfield, config?.zConfig, helloCallback, onCloseCallback) + } + } + /** * Stops the scouting. */ fun stop() { - jniScout?.close() - jniScout = null + zScout?.close() + zScout = null } /** @@ -93,7 +140,7 @@ sealed class Scout ( * CallbackScout scout = Zenoh.scout(hello -> {...}); * ``` */ -class CallbackScout internal constructor(jniScout: JNIScout?) : Scout(jniScout) +class CallbackScout internal constructor(zScout: ZScout) : Scout(zScout) /** * Scout using a handler to handle incoming [Hello] messages. @@ -106,4 +153,4 @@ class CallbackScout internal constructor(jniScout: JNIScout?) : Scout(jniScout) * @param R The type of the receiver. * @param receiver The receiver of the scout's handler. */ -class HandlerScout internal constructor(jniScout: JNIScout?, val receiver: R) : Scout(jniScout) +class HandlerScout internal constructor(zScout: ZScout, val receiver: R) : Scout(zScout) diff --git a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt b/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt index 8da47656..b7b9e76b 100644 --- a/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt +++ b/zenoh-java/src/jvmMain/kotlin/io/zenoh/Zenoh.kt @@ -25,7 +25,7 @@ import java.util.zip.ZipInputStream * log level configuration. */ internal actual object ZenohLoad { - private const val ZENOH_LIB_NAME = "zenoh_jni" + private const val ZENOH_LIB_NAME = "zenoh_flat_jni" init { // Try first to load the local native library for cases in which the module was built locally, diff --git a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java index adb59541..79cdd1c7 100644 --- a/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java +++ b/zenoh-java/src/jvmTest/java/io/zenoh/QueryableTest.java @@ -196,6 +196,23 @@ public void queryReplyErrorTest() throws ZError, InterruptedException { assertEquals(errorMessage, errorReply.getError()); } + /** + * A queryable callback that throws must not crash the JVM: the migrated + * queryable path swallows/logs the exception. (Regression guard for the + * former legacy `on_query` double-free.) + */ + @Test + public void throwingQueryableCallbackDoesNotCrashJvm() throws ZError, InterruptedException { + try (var queryable = session.declareQueryable(testKeyExpr, query -> { + throw new RuntimeException("boom from queryable callback"); + })) { + session.get(testKeyExpr); + Thread.sleep(500); + } + // Reaching here (no JVM abort) means the queryable path handles a + // throwing callback gracefully. + } + @Test public void queryReplyDeleteTest() throws ZError, InterruptedException { var timestamp = TimeStamp.getCurrentTime(); diff --git a/zenoh-jni/Cargo.toml b/zenoh-jni/Cargo.toml deleted file mode 100644 index a88e31ec..00000000 --- a/zenoh-jni/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2023 ZettaScale Technology -# -# This program and the accompanying materials are made available under the -# terms of the Eclipse Public License 2.0 which is available at -# http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -# which is available at https://www.apache.org/licenses/LICENSE-2.0. -# -# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -# -# Contributors: -# ZettaScale Zenoh Team, -# - -[package] -rust-version = "1.75.0" -version = "1.9.0" -repository = "https://github.com/eclipse-zenoh/zenoh" -homepage = "http://zenoh.io" -edition = "2021" -license = "EPL-2.0 OR Apache-2.0" -categories = ["network-programming"] -description = "Zenoh: Zero Overhead Pub/sub, Store/Query and Compute." -name = "zenoh_jni" - -[features] -default = ["zenoh/default", "zenoh-ext"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] -android-logd-logger = "0.4.0" -async-std = { version = "=1.12.0", default-features = false } -clap = "3.2.23" -jni = "0.21.1" -flume = "0.10.14" -uhlc = "0.8.0" -json5 = "0.4.1" -serde_yaml = "0.9.19" -zenoh = { version = "1.9.0", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", features = ["unstable", "internal"], default-features = false } -zenoh-ext = { version = "1.9.0", git = "https://github.com/eclipse-zenoh/zenoh.git", branch = "main", features = ["internal"], default-features = false, optional = true } -tracing = { version = "0.1" , features = ["log"] } -[lib] -name = "zenoh_jni" -crate_type = ["staticlib", "dylib"] - -[build-dependencies] -rustc_version = "0.4.0" - -[profile.release] -debug = false # If you want debug symbol in release mode, set the env variable: RUSTFLAGS=-g -lto = "fat" -codegen-units = 1 -opt-level = 3 -panic = "abort" diff --git a/zenoh-jni/src/config.rs b/zenoh-jni/src/config.rs deleted file mode 100644 index 0ada1340..00000000 --- a/zenoh-jni/src/config.rs +++ /dev/null @@ -1,185 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::{ptr::null, sync::Arc}; - -use jni::{ - objects::{JClass, JString}, - sys::jstring, - JNIEnv, -}; -use zenoh::Config; - -use crate::{errors::ZResult, zerror}; -use crate::{throw_exception, utils::decode_string}; - -/// Loads the default configuration, returning a raw pointer to it. -/// -/// The pointer to the config is expected to be freed later on upon the destruction of the -/// Kotlin Config instance. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_loadDefaultConfigViaJNI( - _env: JNIEnv, - _class: JClass, -) -> *const Config { - let config = Config::default(); - Arc::into_raw(Arc::new(config)) -} - -/// Loads the config from a file, returning a pointer to the loaded config in case of success. -/// In case of failure, an exception is thrown via JNI. -/// -/// The pointer to the config is expected to be freed later on upon the destruction of the -/// Kotlin Config instance. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_loadConfigFileViaJNI( - mut env: JNIEnv, - _class: JClass, - config_path: JString, -) -> *const Config { - || -> ZResult<*const Config> { - let config_file_path = decode_string(&mut env, &config_path)?; - let config = Config::from_file(config_file_path).map_err(|err| zerror!(err))?; - Ok(Arc::into_raw(Arc::new(config))) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }) -} - -/// Loads the config from a json/json5 formatted string, returning a pointer to the loaded config -/// in case of success. In case of failure, an exception is thrown via JNI. -/// -/// The pointer to the config is expected to be freed later on upon the destruction of the -/// Kotlin Config instance. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_loadJsonConfigViaJNI( - mut env: JNIEnv, - _class: JClass, - json_config: JString, -) -> *const Config { - || -> ZResult<*const Config> { - let json_config = decode_string(&mut env, &json_config)?; - let mut deserializer = - json5::Deserializer::from_str(&json_config).map_err(|err| zerror!(err))?; - let config = Config::from_deserializer(&mut deserializer).map_err(|err| match err { - Ok(c) => zerror!("Invalid configuration: {}", c), - Err(e) => zerror!("JSON error: {}", e), - })?; - Ok(Arc::into_raw(Arc::new(config))) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }) -} - -/// Loads the config from a yaml-formatted string, returning a pointer to the loaded config -/// in case of success. In case of failure, an exception is thrown via JNI. -/// -/// The pointer to the config is expected to be freed later on upon the destruction of the -/// Kotlin Config instance. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_loadYamlConfigViaJNI( - mut env: JNIEnv, - _class: JClass, - yaml_config: JString, -) -> *const Config { - || -> ZResult<*const Config> { - let yaml_config = decode_string(&mut env, &yaml_config)?; - let deserializer = serde_yaml::Deserializer::from_str(&yaml_config); - let config = Config::from_deserializer(deserializer).map_err(|err| match err { - Ok(c) => zerror!("Invalid configuration: {}", c), - Err(e) => zerror!("YAML error: {}", e), - })?; - Ok(Arc::into_raw(Arc::new(config))) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }) -} - -/// Returns the json value associated to the provided [key]. May throw an exception in case of failure, which must be handled -/// on the kotlin layer. -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_getJsonViaJNI( - mut env: JNIEnv, - _class: JClass, - cfg_ptr: *const Config, - key: JString, -) -> jstring { - let arc_cfg: Arc = Arc::from_raw(cfg_ptr); - let result = || -> ZResult { - let key = decode_string(&mut env, &key)?; - let json = arc_cfg.get_json(&key).map_err(|err| zerror!(err))?; - let java_json = env.new_string(json).map_err(|err| zerror!(err))?; - Ok(java_json.as_raw()) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - JString::default().as_raw() - }); - std::mem::forget(arc_cfg); - result -} - -/// Inserts a json5 value associated to the provided [key]. May throw an exception in case of failure, which must be handled -/// on the kotlin layer. -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_insertJson5ViaJNI( - mut env: JNIEnv, - _class: JClass, - cfg_ptr: *const Config, - key: JString, - value: JString, -) { - || -> ZResult<()> { - let key = decode_string(&mut env, &key)?; - let value = decode_string(&mut env, &value)?; - let mut config = core::ptr::read(cfg_ptr); - let insert_result = config - .insert_json5(&key, &value) - .map_err(|err| zerror!(err)); - core::ptr::write(cfg_ptr as *mut _, config); - insert_result - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - }) -} - -/// Frees the pointer to the config. The pointer should be valid and should have been obtained through -/// one of the preceding `load` functions. This function should be called upon destruction of the kotlin -/// Config instance. -#[no_mangle] -#[allow(non_snake_case)] -pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIConfig_00024Companion_freePtrViaJNI( - _env: JNIEnv, - _: JClass, - config_ptr: *const Config, -) { - Arc::from_raw(config_ptr); -} diff --git a/zenoh-jni/src/errors.rs b/zenoh-jni/src/errors.rs deleted file mode 100644 index 23687d4c..00000000 --- a/zenoh-jni/src/errors.rs +++ /dev/null @@ -1,59 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::fmt; - -use jni::JNIEnv; - -#[macro_export] -macro_rules! throw_exception { - ($env:expr, $err:expr) => {{ - let _ = $err.throw_on_jvm(&mut $env).map_err(|err| { - tracing::error!("Unable to throw exception: {}", err); - }); - }}; -} - -#[macro_export] -macro_rules! zerror { - ($arg:expr) => { - $crate::errors::ZError($arg.to_string()) - }; - ($fmt:expr, $($arg:tt)*) => { - $crate::errors::ZError(format!($fmt, $($arg)*)) - }; -} - -pub(crate) type ZResult = core::result::Result; - -#[derive(Debug)] -pub(crate) struct ZError(pub String); - -impl fmt::Display for ZError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl ZError { - const KOTLIN_EXCEPTION_NAME: &'static str = "io/zenoh/exceptions/ZError"; - - pub fn throw_on_jvm(&self, env: &mut JNIEnv) -> ZResult<()> { - let exception_class = env - .find_class(Self::KOTLIN_EXCEPTION_NAME) - .map_err(|err| zerror!("Failed to retrieve exception class: {}", err))?; - env.throw_new(exception_class, self.to_string()) - .map_err(|err| zerror!("Failed to throw exception: {}", err)) - } -} diff --git a/zenoh-jni/src/key_expr.rs b/zenoh-jni/src/key_expr.rs deleted file mode 100644 index 11d39d47..00000000 --- a/zenoh-jni/src/key_expr.rs +++ /dev/null @@ -1,333 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::ops::Deref; -use std::sync::Arc; - -use jni::objects::JClass; -use jni::sys::{jboolean, jint, jstring}; -use jni::{objects::JString, JNIEnv}; -use zenoh::key_expr::KeyExpr; - -use crate::errors::ZResult; -use crate::utils::decode_string; -use crate::{throw_exception, zerror}; - -/// Validates the provided `key_expr` to be a valid key expression, returning it back -/// in case of success or throwing an exception in case of failure. -/// -/// # Parameters: -/// `env`: The JNI environment. -/// `_class`: the Java class (unused). -/// `key_expr`: Java string representation of the intended key expression. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_tryFromViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr: JString, -) -> jstring { - validate_key_expr(&mut env, &key_expr) - .map(|_| **key_expr) - .unwrap_or_else(|err| { - throw_exception!(env, err); - JString::default().as_raw() - }) -} - -/// Returns a java string representation of the autocanonized version of the provided `key_expr`. -/// In case of failure and exception will be thrown. -/// -/// # Parameters: -/// `env`: The JNI environment. -/// `_class`: the Java class (unused). -/// `key_expr`: Java string representation of the intended key expression. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_autocanonizeViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr: JString, -) -> jstring { - autocanonize_key_expr(&mut env, &key_expr) - .and_then(|key_expr| { - env.new_string(key_expr.to_string()) - .map(|kexp| kexp.as_raw()) - .map_err(|err| zerror!(err)) - }) - .unwrap_or_else(|err| { - throw_exception!(env, err); - JString::default().as_raw() - }) -} - -/// Returns true in case key_expr_1 intersects key_expr_2. -/// -/// # Params: -/// - `key_expr_ptr_1`: Pointer to the key expression 1, differs from null only if it's a declared key expr. -/// - `key_expr_str_1`: String representation of the key expression 1. -/// - `key_expr_ptr_2`: Pointer to the key expression 2, differs from null only if it's a declared key expr. -/// - `key_expr_str_2`: String representation of the key expression 2. -/// -/// # Safety -/// - This function is marked as unsafe due to raw pointer manipulation, which happens only when providing -/// key expressions that were declared from a session (in that case the key expression has a pointer associated). -/// -/// In that case, this function assumes the pointers are valid pointers to key expressions and those pointers -/// remain valid after the call to this function. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_intersectsViaJNI( - mut env: JNIEnv, - _: JClass, - key_expr_ptr_1: /*nullable*/ *const KeyExpr<'static>, - key_expr_str_1: JString, - key_expr_ptr_2: /*nullable*/ *const KeyExpr<'static>, - key_expr_str_2: JString, -) -> jboolean { - || -> ZResult { - let key_expr_1 = process_kotlin_key_expr(&mut env, &key_expr_str_1, key_expr_ptr_1)?; - let key_expr_2 = process_kotlin_key_expr(&mut env, &key_expr_str_2, key_expr_ptr_2)?; - Ok(key_expr_1.intersects(&key_expr_2) as jboolean) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - false as jboolean - }) -} - -/// Returns true in case key_expr_1 includes key_expr_2. -/// -/// # Params: -/// - `key_expr_ptr_1`: Pointer to the key expression 1, differs from null only if it's a declared key expr. -/// - `key_expr_str_1`: String representation of the key expression 1. -/// - `key_expr_ptr_2`: Pointer to the key expression 2, differs from null only if it's a declared key expr. -/// - `key_expr_str_2`: String representation of the key expression 2. -/// -/// # Safety -/// - This function is marked as unsafe due to raw pointer manipulation, which happens only when providing -/// key expressions that were declared from a session (in that case the key expression has a pointer associated). -/// -/// In that case, this function assumes the pointers are valid pointers to key expressions and those pointers -/// remain valid after the call to this function. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_includesViaJNI( - mut env: JNIEnv, - _: JClass, - key_expr_ptr_1: /*nullable*/ *const KeyExpr<'static>, - key_expr_str_1: JString, - key_expr_ptr_2: /*nullable*/ *const KeyExpr<'static>, - key_expr_str_2: JString, -) -> jboolean { - || -> ZResult { - let key_expr_1 = process_kotlin_key_expr(&mut env, &key_expr_str_1, key_expr_ptr_1)?; - let key_expr_2 = process_kotlin_key_expr(&mut env, &key_expr_str_2, key_expr_ptr_2)?; - Ok(key_expr_1.includes(&key_expr_2) as jboolean) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - false as jboolean - }) -} - -/// Returns the integer representation of the intersection level of the key expression 1 and key expression 2, -/// from the perspective of key expression 1. -/// -/// # Params: -/// - `key_expr_ptr_1`: Pointer to the key expression 1, differs from null only if it's a declared key expr. -/// - `key_expr_str_1`: String representation of the key expression 1. -/// - `key_expr_ptr_2`: Pointer to the key expression 2, differs from null only if it's a declared key expr. -/// - `key_expr_str_2`: String representation of the key expression 2. -/// -/// # Safety -/// - This function is marked as unsafe due to raw pointer manipulation, which happens only when providing -/// key expressions that were declared from a session (in that case the key expression has a pointer associated). -/// -/// In that case, this function assumes the pointers are valid pointers to key expressions and those pointers -/// remain valid after the call to this function. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_relationToViaJNI( - mut env: JNIEnv, - _: JClass, - key_expr_ptr_1: /*nullable*/ *const KeyExpr<'static>, - key_expr_str_1: JString, - key_expr_ptr_2: /*nullable*/ *const KeyExpr<'static>, - key_expr_str_2: JString, -) -> jint { - || -> ZResult { - let key_expr_1 = process_kotlin_key_expr(&mut env, &key_expr_str_1, key_expr_ptr_1)?; - let key_expr_2 = process_kotlin_key_expr(&mut env, &key_expr_str_2, key_expr_ptr_2)?; - Ok(key_expr_1.relation_to(&key_expr_2) as jint) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - -1 as jint - }) -} - -/// Joins key expression 1 with key expression 2, where key_expr_2 is a string. Returns the string representation -/// of the result, or throws an exception in case of failure. -/// -/// # Params: -/// - `key_expr_ptr_1`: Pointer to the key expression 1, differs from null only if it's a declared key expr. -/// - `key_expr_ptr_1`: String representation of the key expression 1. -/// - `key_expr_2`: String representation of the key expression 2. -/// -/// # Safety -/// - This function is marked as unsafe due to raw pointer manipulation, which happens only when providing -/// key expressions that were declared from a session (in that case the key expression has a pointer associated). -/// -/// In that case, this function assumes the pointers are valid pointers to key expressions and those pointers -/// remain valid after the call to this function. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_joinViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr_ptr_1: /*nullable*/ *const KeyExpr<'static>, - key_expr_str_1: JString, - key_expr_2: JString, -) -> jstring { - || -> ZResult { - let key_expr_1 = process_kotlin_key_expr(&mut env, &key_expr_str_1, key_expr_ptr_1)?; - let key_expr_2_str = decode_string(&mut env, &key_expr_2)?; - let result = key_expr_1 - .join(key_expr_2_str.as_str()) - .map_err(|err| zerror!(err))?; - env.new_string(result.to_string()) - .map(|kexp| kexp.as_raw()) - .map_err(|err| zerror!(err)) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - JString::default().as_raw() - }) -} - -/// Concats key_expr_1 with key_expr_2, where key_expr_2 is a string. Returns the string representation -/// of the result, or throws an exception in case of failure. -/// -/// # Params: -/// - `key_expr_ptr_1`: Pointer to the key expression 1, differs from null only if it's a declared key expr. -/// - `key_expr_ptr_1`: String representation of the key expression 1. -/// - `key_expr_2`: String representation of the key expression 2. -/// -/// # Safety -/// - This function is marked as unsafe due to raw pointer manipulation, which happens only when providing -/// key expressions that were declared from a session (in that case the key expression has a pointer associated). -/// -/// In that case, this function assumes the pointers are valid pointers to key expressions and those pointers -/// remain valid after the call to this function. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_00024Companion_concatViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr_ptr_1: /*nullable*/ *const KeyExpr<'static>, - key_expr_str_1: JString, - key_expr_2: JString, -) -> jstring { - || -> ZResult { - let key_expr_1 = process_kotlin_key_expr(&mut env, &key_expr_str_1, key_expr_ptr_1)?; - let key_expr_2_str = decode_string(&mut env, &key_expr_2)?; - let result = key_expr_1 - .concat(key_expr_2_str.as_str()) - .map_err(|err| zerror!(err))?; - env.new_string(result.to_string()) - .map(|kexp| kexp.as_raw()) - .map_err(|err| zerror!(err)) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - JString::default().as_raw() - }) -} - -/// Frees a declared key expression. -/// -/// # Parameters -/// - `_env`: Unused. The JNI environment. -/// - `_class`: Unused. The java class from which the function was called. -/// - `key_expr_ptr`: the pointer to the key expression. -/// -/// # Safety -/// - This function assumes the provided pointer is valid and points to a native key expression. -/// - The memory associated to the pointer is freed after returning from this call, turning the -/// pointer invalid after that. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIKeyExpr_freePtrViaJNI( - _env: JNIEnv, - _: JClass, - key_expr_ptr: *const KeyExpr<'static>, -) { - Arc::from_raw(key_expr_ptr); -} - -fn validate_key_expr(env: &mut JNIEnv, key_expr: &JString) -> ZResult> { - let key_expr_str = decode_string(env, key_expr) - .map_err(|err| zerror!("Unable to get key expression string value: '{}'.", err))?; - - KeyExpr::try_from(key_expr_str) - .map_err(|err| zerror!("Unable to create key expression: '{}'.", err)) -} - -fn autocanonize_key_expr(env: &mut JNIEnv, key_expr: &JString) -> ZResult> { - decode_string(env, key_expr) - .map_err(|err| zerror!("Unable to get key expression string value: '{}'.", err)) - .and_then(|key_expr_str| { - KeyExpr::autocanonize(key_expr_str) - .map_err(|err| zerror!("Unable to create key expression: '{}'", err)) - }) -} - -/// Processes a kotlin key expression. -/// -/// Receives the Java/Kotlin string representation of the key expression as well as a pointer. -/// The pointer is only valid in cases where the key expression is associated to a native pointer -/// (when the key expression was declared from a session). -/// If the pointer is valid, the key expression returned is the key expression the pointer pointed to. -/// Otherwise, a key expression created from the string representation of the key expression is returned. -/// -/// # Safety: -/// -/// The key_expr_str argument provided should already have been validated upon creation of the -/// KeyExpr instance on Kotlin. -/// -pub(crate) unsafe fn process_kotlin_key_expr( - env: &mut JNIEnv, - key_expr_str: &JString, - key_expr_ptr: *const KeyExpr<'static>, -) -> ZResult> { - if key_expr_ptr.is_null() { - let key_expr = decode_string(env, key_expr_str) - .map_err(|err| zerror!("Unable to get key expression string value: '{}'.", err))?; - Ok(KeyExpr::from_string_unchecked(key_expr)) - } else { - let key_expr = Arc::from_raw(key_expr_ptr); - let key_expr_clone = key_expr.deref().clone(); - std::mem::forget(key_expr); - Ok(key_expr_clone) - } -} diff --git a/zenoh-jni/src/lib.rs b/zenoh-jni/src/lib.rs deleted file mode 100644 index ff3981a4..00000000 --- a/zenoh-jni/src/lib.rs +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -mod config; -mod errors; -mod key_expr; -mod liveliness; -mod logger; -mod publisher; -mod querier; -mod query; -mod queryable; -mod scouting; -mod session; -mod subscriber; -mod utils; -#[cfg(feature = "zenoh-ext")] -mod zbytes; -mod zenoh_id; - -// Test should be runned with `cargo test --no-default-features` -#[test] -#[cfg(not(feature = "default"))] -fn test_no_default_features() { - assert_eq!(zenoh::FEATURES, concat!(" zenoh/unstable")); -} diff --git a/zenoh-jni/src/liveliness.rs b/zenoh-jni/src/liveliness.rs deleted file mode 100644 index 8b05c925..00000000 --- a/zenoh-jni/src/liveliness.rs +++ /dev/null @@ -1,242 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::{ptr::null, sync::Arc, time::Duration}; - -use jni::{ - objects::{JByteArray, JClass, JObject, JString, JValue}, - sys::{jboolean, jint, jlong}, - JNIEnv, -}; - -use zenoh::{ - internal::runtime::ZRuntime, key_expr::KeyExpr, liveliness::LivelinessToken, - pubsub::Subscriber, sample::Sample, Session, Wait, -}; - -use crate::{ - errors::ZResult, - key_expr::process_kotlin_key_expr, - session::{on_reply_error, on_reply_success}, - throw_exception, - utils::{ - bytes_to_java_array, get_callback_global_ref, get_java_vm, load_on_close, - slice_to_java_string, - }, - zerror, -}; - -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNILiveliness_getViaJNI( - mut env: JNIEnv, - _class: JClass, - session_ptr: *const Session, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - callback: JObject, - timeout_ms: jlong, - on_close: JObject, -) { - let session = unsafe { Arc::from_raw(session_ptr) }; - let _ = || -> ZResult<()> { - let key_expr = unsafe { process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr) }?; - let java_vm = Arc::new(get_java_vm(&mut env)?); - let callback_global_ref = get_callback_global_ref(&mut env, callback)?; - let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; - let on_close = load_on_close(&java_vm, on_close_global_ref); - let timeout = Duration::from_millis(timeout_ms as u64); - let replies = session - .liveliness() - .get(key_expr.to_owned()) - .timeout(timeout) - .wait() - .map_err(|err| zerror!(err))?; - - ZRuntime::Application.spawn(async move { - on_close.noop(); // Does nothing, but moves `on_close` inside the closure so it gets destroyed with the closure - while let Ok(reply) = replies.recv_async().await { - || -> ZResult<()> { - tracing::debug!("Receiving liveliness reply through JNI: {:?}", reply); - let mut env = java_vm.attach_current_thread_as_daemon().map_err(|err| { - zerror!( - "Unable to attach thread for GET liveliness query callback: {}.", - err - ) - })?; - match reply.result() { - Ok(sample) => on_reply_success( - &mut env, - reply.replier_id(), - sample, - &callback_global_ref, - ), - Err(error) => on_reply_error( - &mut env, - reply.replier_id(), - error, - &callback_global_ref, - ), - } - }() - .unwrap_or_else(|err| tracing::error!("Error on get liveliness callback: {err}.")); - } - }); - Ok(()) - }() - .map_err(|err| { - throw_exception!(env, err); - }); - std::mem::forget(session); -} - -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNILiveliness_declareTokenViaJNI( - mut env: JNIEnv, - _class: JClass, - session_ptr: *const Session, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, -) -> *const LivelinessToken { - let session = unsafe { Arc::from_raw(session_ptr) }; - let ptr = || -> ZResult<*const LivelinessToken> { - let key_expr = unsafe { process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr) }?; - tracing::trace!("Declaring liveliness token on '{key_expr}'."); - let token = session - .liveliness() - .declare_token(key_expr) - .wait() - .map_err(|err| zerror!(err))?; - Ok(Arc::into_raw(Arc::new(token))) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }); - std::mem::forget(session); - ptr -} - -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNILivelinessToken_00024Companion_undeclareViaJNI( - _env: JNIEnv, - _: JClass, - token_ptr: *const LivelinessToken, -) { - unsafe { Arc::from_raw(token_ptr) }; -} - -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNILiveliness_declareSubscriberViaJNI( - mut env: JNIEnv, - _class: JClass, - session_ptr: *const Session, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - callback: JObject, - history: jboolean, - on_close: JObject, -) -> *const Subscriber<()> { - let session = unsafe { Arc::from_raw(session_ptr) }; - || -> ZResult<*const Subscriber<()>> { - let java_vm = Arc::new(get_java_vm(&mut env)?); - let callback_global_ref = get_callback_global_ref(&mut env, callback)?; - let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; - let on_close = load_on_close(&java_vm, on_close_global_ref); - - let key_expr = unsafe { process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr) }?; - tracing::debug!("Declaring liveliness subscriber on '{}'...", key_expr); - - let result = session - .liveliness() - .declare_subscriber(key_expr.to_owned()) - .history(history != 0) - .callback(move |sample: Sample| { - let _ = || -> ZResult<()> { - on_close.noop(); // Does nothing, but moves `on_close` inside the closure so it gets destroyed with the closure - let mut env = java_vm.attach_current_thread_as_daemon().map_err(|err| { - zerror!("Unable to attach thread for liveliness subscriber: {}", err) - })?; - let byte_array = bytes_to_java_array(&env, sample.payload()) - .map(|array| env.auto_local(array))?; - - let encoding_id: jint = sample.encoding().id() as jint; - let encoding_schema = match sample.encoding().schema() { - Some(schema) => slice_to_java_string(&env, schema)?, - None => JString::default(), - }; - let kind = sample.kind() as jint; - let (timestamp, is_valid) = sample - .timestamp() - .map(|timestamp| (timestamp.get_time().as_u64(), true)) - .unwrap_or((0, false)); - - let attachment_bytes = sample - .attachment() - .map_or_else( - || Ok(JByteArray::default()), - |attachment| bytes_to_java_array(&env, attachment), - ) - .map(|array| env.auto_local(array)) - .map_err(|err| zerror!("Error processing attachment: {}", err))?; - - let key_expr_str = env.auto_local( - env.new_string(sample.key_expr().to_string()) - .map_err(|err| zerror!("Error processing sample key expr: {}", err))?, - ); - - let express = sample.express(); - let priority = sample.priority() as jint; - let cc = sample.congestion_control() as jint; - - env.call_method( - &callback_global_ref, - "run", - "(Ljava/lang/String;[BILjava/lang/String;IJZ[BZII)V", - &[ - JValue::from(&key_expr_str), - JValue::from(&byte_array), - JValue::from(encoding_id), - JValue::from(&encoding_schema), - JValue::from(kind), - JValue::from(timestamp as i64), - JValue::from(is_valid), - JValue::from(&attachment_bytes), - JValue::from(express), - JValue::from(priority), - JValue::from(cc), - ], - ) - .map_err(|err| zerror!(err))?; - Ok(()) - }() - .map_err(|err| tracing::error!("On liveliness subscriber callback error: {err}")); - }) - .wait(); - - let subscriber = - result.map_err(|err| zerror!("Unable to declare liveliness subscriber: {}", err))?; - - tracing::debug!("Subscriber declared on '{}'.", key_expr); - std::mem::forget(session); - Ok(Arc::into_raw(Arc::new(subscriber))) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }) -} diff --git a/zenoh-jni/src/logger.rs b/zenoh-jni/src/logger.rs deleted file mode 100644 index 785a6cd1..00000000 --- a/zenoh-jni/src/logger.rs +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use jni::{ - objects::{JClass, JString}, - JNIEnv, -}; - -use crate::{errors::ZResult, throw_exception, zerror}; - -/// Redirects the Rust logs either to logcat for Android systems or to the standard output (for non-Android systems). -/// -/// This function is meant to be called from Java/Kotlin code through JNI. It takes a `filter` -/// indicating the desired log level. -/// If the logger was already initialized in a previous call, then it does nothing. -/// -/// See https://docs.rs/env_logger/latest/env_logger/index.html for accepted filter format. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `filter`: The logs filter. -/// -/// # Errors: -/// - If there is an error parsing the log level string, a `JNIException` is thrown on the JVM. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_Logger_00024Companion_startLogsViaJNI( - mut env: JNIEnv, - _class: JClass, - filter: JString, -) { - || -> ZResult<()> { - let log_level = parse_filter(&mut env, filter)?; - android_logd_logger::builder() - .parse_filters(log_level.as_str()) - .tag_target_strip() - .prepend_module(true) - .try_init() - .ok(); - Ok(()) - }() - .unwrap_or_else(|err| throw_exception!(env, err)) -} - -fn parse_filter(env: &mut JNIEnv, log_level: JString) -> ZResult { - let log_level = env.get_string(&log_level).map_err(|err| zerror!(err))?; - log_level - .to_str() - .map(|level| Ok(level.to_string())) - .map_err(|err| zerror!(err))? -} diff --git a/zenoh-jni/src/publisher.rs b/zenoh-jni/src/publisher.rs deleted file mode 100644 index ead60c3f..00000000 --- a/zenoh-jni/src/publisher.rs +++ /dev/null @@ -1,130 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::sync::Arc; - -use jni::{ - objects::{JByteArray, JClass, JString}, - sys::jint, - JNIEnv, -}; -use zenoh::{pubsub::Publisher, Wait}; - -use crate::throw_exception; -use crate::{ - errors::ZResult, - utils::{decode_byte_array, decode_encoding}, - zerror, -}; - -/// Performs a PUT operation on a Zenoh publisher via JNI. -/// -/// # Parameters -/// - `env`: The JNI environment pointer. -/// - `_class`: The Java class reference (unused). -/// - `payload`: The byte array to be published. -/// - `encoding_id`: The encoding ID of the payload. -/// - `encoding_schema`: Nullable encoding schema string of the payload. -/// - `attachment`: Nullble byte array for the attachment. -/// - `publisher_ptr`: The raw pointer to the Zenoh publisher ([Publisher]). -/// -/// # Safety -/// - This function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - Assumes that the provided publisher pointer is valid and has not been modified or freed. -/// - The publisher pointer remains valid after this function call. -/// - May throw an exception in case of failure, which must be handled by the caller. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIPublisher_putViaJNI( - mut env: JNIEnv, - _class: JClass, - payload: JByteArray, - encoding_id: jint, - encoding_schema: /*nullable*/ JString, - attachment: /*nullable*/ JByteArray, - publisher_ptr: *const Publisher<'static>, -) { - let publisher = Arc::from_raw(publisher_ptr); - let _ = || -> ZResult<()> { - let payload = decode_byte_array(&env, payload)?; - let mut publication = publisher.put(payload); - let encoding = decode_encoding(&mut env, encoding_id, &encoding_schema)?; - publication = publication.encoding(encoding); - if !attachment.is_null() { - let attachment = decode_byte_array(&env, attachment)?; - publication = publication.attachment::>(attachment) - }; - publication.wait().map_err(|err| zerror!(err)) - }() - .map_err(|err| throw_exception!(env, err)); - std::mem::forget(publisher); -} - -/// Performs a DELETE operation on a Zenoh publisher via JNI. -/// -/// # Parameters -/// - `env`: The JNI environment pointer. -/// - `_class`: The Java class reference (unused). -/// - `attachment`: Nullble byte array for the attachment. -/// - `publisher_ptr`: The raw pointer to the Zenoh publisher ([Publisher]). -/// -/// # Safety -/// - This function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - Assumes that the provided publisher pointer is valid and has not been modified or freed. -/// - The publisher pointer remains valid after this function call. -/// - May throw an exception in case of failure, which must be handled by the caller. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIPublisher_deleteViaJNI( - mut env: JNIEnv, - _class: JClass, - attachment: /*nullable*/ JByteArray, - publisher_ptr: *const Publisher<'static>, -) { - let publisher = Arc::from_raw(publisher_ptr); - let _ = || -> ZResult<()> { - let mut delete = publisher.delete(); - if !attachment.is_null() { - let attachment = decode_byte_array(&env, attachment)?; - delete = delete.attachment::>(attachment) - }; - delete.wait().map_err(|err| zerror!(err)) - }() - .map_err(|err| throw_exception!(env, err)); - std::mem::forget(publisher) -} - -/// Frees the publisher. -/// -/// # Parameters: -/// - `_env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `publisher_ptr`: The raw pointer to the Zenoh publisher ([Publisher]). -/// -/// # Safety: -/// - The function is marked as unsafe due to raw pointer manipulation. -/// - It assumes that the provided publisher pointer is valid and has not been modified or freed. -/// - After calling this function, the publisher pointer becomes invalid and should not be used anymore. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIPublisher_freePtrViaJNI( - _env: JNIEnv, - _: JClass, - publisher_ptr: *const Publisher, -) { - Arc::from_raw(publisher_ptr); -} diff --git a/zenoh-jni/src/querier.rs b/zenoh-jni/src/querier.rs deleted file mode 100644 index 8c239498..00000000 --- a/zenoh-jni/src/querier.rs +++ /dev/null @@ -1,137 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::sync::Arc; - -use jni::{ - objects::{JByteArray, JClass, JObject, JString}, - sys::jint, - JNIEnv, -}; -use zenoh::{key_expr::KeyExpr, query::Querier, Wait}; - -use crate::{ - errors::ZResult, - key_expr::process_kotlin_key_expr, - session::{on_reply_error, on_reply_success}, - throw_exception, - utils::{ - decode_byte_array, decode_encoding, decode_string, get_callback_global_ref, get_java_vm, - load_on_close, - }, - zerror, -}; - -/// Perform a Zenoh GET through a querier. -/// -/// This function is meant to be called from Java/Kotlin code through JNI. -/// -/// Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `querier_ptr`: The raw pointer to the querier. -/// - `key_expr_ptr`: A raw pointer to the [KeyExpr] provided to the kotlin querier. May be null in case of using an -/// undeclared key expression. -/// - `key_expr_str`: String representation of the key expression used during the querier declaration. -/// It won't be considered in case a key_expr_ptr to a declared key expression is provided. -/// - `selector_params`: Optional selector parameters for the query. -/// - `callback`: Reference to the Kotlin callback to be run upon receiving a reply. -/// - `on_close`: Reference to a kotlin callback to be run upon finishing the get operation, mostly used for closing a provided channel. -/// - `attachment`: Optional attachment. -/// - `payload`: Optional payload for the query. -/// - `encoding_id`: Encoding id of the payload provided. -/// - `encoding_schema`: Encoding schema of the payload provided. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIQuerier_getViaJNI( - mut env: JNIEnv, - _class: JClass, - querier_ptr: *const Querier, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - selector_params: /*nullable*/ JString, - callback: JObject, - on_close: JObject, - attachment: /*nullable*/ JByteArray, - payload: /*nullable*/ JByteArray, - encoding_id: jint, - encoding_schema: /*nullable*/ JString, -) { - let querier = Arc::from_raw(querier_ptr); - let _ = || -> ZResult<()> { - let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; - let java_vm = Arc::new(get_java_vm(&mut env)?); - let callback_global_ref = get_callback_global_ref(&mut env, callback)?; - let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; - let on_close = load_on_close(&java_vm, on_close_global_ref); - let mut get_builder = querier.get().callback(move |reply| { - || -> ZResult<()> { - on_close.noop(); // Does nothing, but moves `on_close` inside the closure so it gets destroyed with the closure - tracing::debug!("Receiving reply through JNI: {:?}", reply); - let mut env = java_vm.attach_current_thread_as_daemon().map_err(|err| { - zerror!("Unable to attach thread for GET query callback: {}.", err) - })?; - - match reply.result() { - Ok(sample) => { - on_reply_success(&mut env, reply.replier_id(), sample, &callback_global_ref) - } - Err(error) => { - on_reply_error(&mut env, reply.replier_id(), error, &callback_global_ref) - } - } - }() - .unwrap_or_else(|err| tracing::error!("Error on get callback: {err}")); - }); - - if !selector_params.is_null() { - let params = decode_string(&mut env, &selector_params)?; - get_builder = get_builder.parameters(params) - }; - - if !payload.is_null() { - let encoding = decode_encoding(&mut env, encoding_id, &encoding_schema)?; - get_builder = get_builder.encoding(encoding); - get_builder = get_builder.payload(decode_byte_array(&env, payload)?); - } - - if !attachment.is_null() { - let attachment = decode_byte_array(&env, attachment)?; - get_builder = get_builder.attachment::>(attachment); - } - - get_builder - .wait() - .map(|_| tracing::trace!("Performing get on '{key_expr}'.",)) - .map_err(|err| zerror!(err)) - }() - .map_err(|err| throw_exception!(env, err)); - std::mem::forget(querier); -} - -/// -/// Frees the pointer of the querier. -/// -/// After a call to this function, no further jni operations should be performed using the querier associated to the raw pointer provided. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQuerier_freePtrViaJNI( - _env: JNIEnv, - _: JClass, - querier_ptr: *const Querier<'static>, -) { - Arc::from_raw(querier_ptr); -} diff --git a/zenoh-jni/src/query.rs b/zenoh-jni/src/query.rs deleted file mode 100644 index 9c843892..00000000 --- a/zenoh-jni/src/query.rs +++ /dev/null @@ -1,206 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::sync::Arc; - -use crate::utils::{decode_byte_array, decode_encoding}; -use crate::zerror; -use crate::{errors::ZResult, key_expr::process_kotlin_key_expr, throw_exception}; -use jni::{ - objects::{JByteArray, JClass, JString}, - sys::{jboolean, jint, jlong}, - JNIEnv, -}; -use uhlc::ID; -use zenoh::{ - key_expr::KeyExpr, - query::Query, - time::{Timestamp, NTP64}, - Wait, -}; - -/// Replies with `success` to a Zenoh [Query] via JNI, freeing the query in the process. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `query_ptr`: The raw pointer to the Zenoh query. -/// - `key_expr_ptr`: Nullable key expression pointer associated with the query result. This parameter -/// is meant to be used with declared key expressions, which have a pointer associated to them. -/// In case of it being null, then the `key_expr_string` will be used to perform the reply. -/// - `key_expr_str`: The string representation of the key expression associated with the query result. -/// - `payload`: The payload for the reply. -/// - `encoding_id`: The encoding id of the payload. -/// - `encoding_schema`: Nullable encoding schema. -/// - `timestamp_enabled`: A boolean indicating whether the timestamp is enabled. -/// - `timestamp_ntp_64`: The NTP64 timestamp value. -/// - `attachment`: Nullable user attachment encoded as a byte array. -/// - `qos_*`: QoS parameters for the reply. -/// -/// # Safety: -/// - This function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided raw pointer to the Zenoh query is valid and has not been modified or freed. -/// - The query pointer is freed after calling this function (queries shouldn't be replied more than once), -/// therefore the query isn't valid anymore after that. -/// - May throw a JNI exception in case of failure, which should be handled by the caller. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQuery_replySuccessViaJNI( - mut env: JNIEnv, - _class: JClass, - query_ptr: *const Query, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - payload: JByteArray, - encoding_id: jint, - encoding_schema: /*nullable*/ JString, - timestamp_enabled: jboolean, - timestamp_ntp_64: jlong, - attachment: /*nullable*/ JByteArray, - qos_express: jboolean, -) { - let _ = || -> ZResult<()> { - let query = Arc::from_raw(query_ptr); - let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; - let payload = decode_byte_array(&env, payload)?; - let mut reply_builder = query.reply(key_expr, payload); - let encoding = decode_encoding(&mut env, encoding_id, &encoding_schema)?; - reply_builder = reply_builder.encoding(encoding); - if timestamp_enabled != 0 { - let ts = Timestamp::new(NTP64(timestamp_ntp_64 as u64), ID::rand()); - reply_builder = reply_builder.timestamp(ts) - } - if !attachment.is_null() { - reply_builder = reply_builder.attachment(decode_byte_array(&env, attachment)?); - } - reply_builder = reply_builder.express(qos_express != 0); - reply_builder.wait().map_err(|err| zerror!(err)) - }() - .map_err(|err| throw_exception!(env, err)); -} - -/// Replies with `error` to a Zenoh [Query] via JNI, freeing the query in the process. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `query_ptr`: The raw pointer to the Zenoh query. -/// - `payload`: The payload for the reply. -/// - `encoding_id`: The encoding id of the payload. -/// - `encoding_schema`: Nullable encoding schema. -/// -/// # Safety: -/// - This function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided raw pointer to the Zenoh query is valid and has not been modified or freed. -/// - May throw a JNI exception in case of failure, which should be handled by the caller. -/// - The query pointer is freed after calling this function (queries shouldn't be replied more than once), -/// therefore the query isn't valid anymore after that. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQuery_replyErrorViaJNI( - mut env: JNIEnv, - _class: JClass, - query_ptr: *const Query, - payload: JByteArray, - encoding_id: jint, - encoding_schema: /*nullable*/ JString, -) { - let _ = || -> ZResult<()> { - let query = Arc::from_raw(query_ptr); - let encoding = decode_encoding(&mut env, encoding_id, &encoding_schema)?; - query - .reply_err(decode_byte_array(&env, payload)?) - .encoding(encoding) - .wait() - .map_err(|err| zerror!(err)) - }() - .map_err(|err| throw_exception!(env, err)); -} - -/// Replies with `delete` to a Zenoh [Query] via JNI, freeing the query in the process. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `query_ptr`: The raw pointer to the Zenoh query. -/// - `key_expr_ptr`: Nullable key expression pointer associated with the query result. This parameter -/// is meant to be used with declared key expressions, which have a pointer associated to them. -/// In case of it being null, then the `key_expr_string` will be used to perform the reply. -/// - `key_expr_str`: The string representation of the key expression associated with the query result. -/// - `timestamp_enabled`: A boolean indicating whether the timestamp is enabled. -/// - `timestamp_ntp_64`: The NTP64 timestamp value. -/// - `attachment`: Nullable user attachment encoded as a byte array. -/// - `qos_*`: QoS parameters for the reply. -/// -/// # Safety: -/// - This function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided raw pointer to the Zenoh query is valid and has not been modified or freed. -/// - May throw a JNI exception in case of failure, which should be handled by the caller. -/// - The query pointer is freed after calling this function (queries shouldn't be replied more than once), -/// therefore the query isn't valid anymore after that. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQuery_replyDeleteViaJNI( - mut env: JNIEnv, - _class: JClass, - query_ptr: *const Query, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - timestamp_enabled: jboolean, - timestamp_ntp_64: jlong, - attachment: /*nullable*/ JByteArray, - qos_express: jboolean, -) { - let _ = || -> ZResult<()> { - let query = Arc::from_raw(query_ptr); - let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; - let mut reply_builder = query.reply_del(key_expr); - if timestamp_enabled != 0 { - let ts = Timestamp::new(NTP64(timestamp_ntp_64 as u64), ID::rand()); - reply_builder = reply_builder.timestamp(ts) - } - if !attachment.is_null() { - reply_builder = reply_builder.attachment(decode_byte_array(&env, attachment)?); - } - reply_builder = reply_builder.express(qos_express != 0); - reply_builder.wait().map_err(|err| zerror!(err)) - }() - .map_err(|err| throw_exception!(env, err)); -} - -/// Frees the Query via JNI. -/// -/// Parameters: -/// - `_env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `ptr`: The raw pointer to the Zenoh query ([Query]). -/// -/// Safety: -/// - The function is marked as unsafe due to raw pointer manipulation. -/// - It assumes that the provided query pointer is valid and has not been modified or freed. -/// - The function takes ownership of the raw pointer and releases the associated memory. -/// - After calling this function, the query pointer becomes invalid and should not be used anymore. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQuery_freePtrViaJNI( - _env: JNIEnv, - _: JClass, - query_ptr: *const Query, -) { - Arc::from_raw(query_ptr); -} diff --git a/zenoh-jni/src/queryable.rs b/zenoh-jni/src/queryable.rs deleted file mode 100644 index 5d2ddb1d..00000000 --- a/zenoh-jni/src/queryable.rs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::sync::Arc; - -use jni::{objects::JClass, JNIEnv}; -use zenoh::query::Queryable; - -/// Frees the [Queryable]. -/// -/// # Parameters: -/// - `_env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `queryable_ptr`: The raw pointer to the Zenoh queryable ([Queryable]). -/// -/// # Safety: -/// - The function is marked as unsafe due to raw pointer manipulation. -/// - It assumes that the provided queryable pointer is valid and has not been modified or freed. -/// - The function takes ownership of the raw pointer and releases the associated memory. -/// - After calling this function, the queryable pointer becomes invalid and should not be used anymore. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIQueryable_freePtrViaJNI( - _env: JNIEnv, - _: JClass, - queryable_ptr: *const Queryable<()>, -) { - Arc::from_raw(queryable_ptr); -} diff --git a/zenoh-jni/src/scouting.rs b/zenoh-jni/src/scouting.rs deleted file mode 100644 index b0a665c1..00000000 --- a/zenoh-jni/src/scouting.rs +++ /dev/null @@ -1,113 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::{ptr::null, sync::Arc}; - -use jni::{ - objects::{GlobalRef, JClass, JList, JObject, JValue}, - sys::jint, - JNIEnv, -}; -use zenoh::{config::WhatAmIMatcher, Wait}; -use zenoh::{scouting::Scout, Config}; - -use crate::utils::{get_callback_global_ref, get_java_vm, load_on_close}; -use crate::{errors::ZResult, throw_exception, zerror}; - -/// Start a scout. -/// -/// # Params -/// - `whatAmI`: Ordinal value of the WhatAmI enum. -/// - `callback`: Callback to be executed whenever a hello message is received. -/// - `config_ptr`: Optional config pointer. -/// -/// Returns a pointer to the scout, which must be freed afterwards. -/// If starting the scout fails, an exception is thrown on the JVM, and a null pointer is returned. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNIScout_00024Companion_scoutViaJNI( - mut env: JNIEnv, - _class: JClass, - whatAmI: jint, - callback: JObject, - on_close: JObject, - config_ptr: /*nullable=*/ *const Config, -) -> *const Scout<()> { - || -> ZResult<*const Scout<()>> { - let callback_global_ref = get_callback_global_ref(&mut env, callback)?; - let java_vm = Arc::new(get_java_vm(&mut env)?); - let on_close_global_ref: GlobalRef = get_callback_global_ref(&mut env, on_close)?; - let on_close = load_on_close(&java_vm, on_close_global_ref); - let whatAmIMatcher: WhatAmIMatcher = (whatAmI as u8).try_into().unwrap(); // The validity of the operation is guaranteed on the kotlin layer. - let config = if config_ptr.is_null() { - Config::default() - } else { - let arc_cfg = Arc::from_raw(config_ptr); - let config_clone = arc_cfg.as_ref().clone(); - std::mem::forget(arc_cfg); - config_clone - }; - zenoh::scout(whatAmIMatcher, config) - .callback(move |hello| { - on_close.noop(); // Moves `on_close` inside the closure so it gets destroyed with the closure - tracing::debug!("Received hello: {hello}"); - let _ = || -> jni::errors::Result<()> { - let mut env = java_vm.attach_current_thread_as_daemon()?; - let whatami = hello.whatami() as jint; - let zenoh_id = env - .byte_array_from_slice(&hello.zid().to_le_bytes()) - .map(|it| env.auto_local(it))?; - let locators = env - .new_object("java/util/ArrayList", "()V", &[]) - .map(|it| env.auto_local(it))?; - let jlist = JList::from_env(&mut env, &locators)?; - for value in hello.locators() { - let locator = env.new_string(value.as_str())?; - jlist.add(&mut env, &locator)?; - } - env.call_method( - &callback_global_ref, - "run", - "(I[BLjava/util/List;)V", - &[ - JValue::from(whatami), - JValue::from(&zenoh_id), - JValue::from(&locators), - ], - )?; - Ok(()) - }() - .map_err(|err| tracing::error!("Error while scouting: ${err}")); - }) - .wait() - .map(|scout| Arc::into_raw(Arc::new(scout))) - .map_err(|err| zerror!(err)) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }) -} - -/// Frees the scout. -#[no_mangle] -#[allow(non_snake_case)] -pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNIScout_00024Companion_freePtrViaJNI( - _env: JNIEnv, - _: JClass, - scout_ptr: *const Scout<()>, -) { - Arc::from_raw(scout_ptr); -} diff --git a/zenoh-jni/src/session.rs b/zenoh-jni/src/session.rs deleted file mode 100644 index 5f0848b2..00000000 --- a/zenoh-jni/src/session.rs +++ /dev/null @@ -1,1201 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::{mem, ops::Deref, ptr::null, sync::Arc, time::Duration}; - -use jni::{ - objects::{GlobalRef, JByteArray, JClass, JList, JObject, JString, JValue}, - sys::{jboolean, jbyteArray, jint, jlong, jobject}, - JNIEnv, -}; -use zenoh::{ - config::Config, - key_expr::KeyExpr, - pubsub::{Publisher, Subscriber}, - query::{Querier, Query, Queryable, ReplyError, ReplyKeyExpr, Selector}, - sample::Sample, - session::{EntityGlobalId, Session, ZenohId}, - Wait, -}; - -use crate::{ - errors::ZResult, key_expr::process_kotlin_key_expr, throw_exception, utils::*, zerror, -}; - -/// Open a Zenoh session via JNI. -/// -/// It returns an [Arc] raw pointer to the Zenoh Session, which should be stored as a private read-only attribute -/// of the session object in the Java/Kotlin code. Subsequent calls to other session functions will require -/// this raw pointer to retrieve the [Session] using `Arc::from_raw`. -/// -/// If opening the session fails, an exception is thrown on the JVM, and a null pointer is returned. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class (parameter required by the JNI interface but unused). -/// - `config_path`: Nullable path to the Zenoh config file. If null, the default configuration will be loaded. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_00024Companion_openSessionViaJNI( - mut env: JNIEnv, - _class: JClass, - config_ptr: *const Config, -) -> *const Session { - let session = open_session(config_ptr); - match session { - Ok(session) => Arc::into_raw(Arc::new(session)), - Err(err) => { - tracing::error!("Unable to open session: {}", err); - throw_exception!(env, zerror!(err)); - null() - } - } -} - -/// Open a Zenoh session with the configuration pointed out by `config_path`. -/// -/// If the config path provided is null then the default configuration is loaded. -/// -unsafe fn open_session(config_ptr: *const Config) -> ZResult { - let config = Arc::from_raw(config_ptr); - let result = zenoh::open(config.as_ref().clone()) - .wait() - .map_err(|err| zerror!(err)); - mem::forget(config); - result -} - -/// Open a Zenoh session with a JSON configuration. -/// -/// It returns an [Arc] raw pointer to the Zenoh Session, which should be stored as a private read-only attribute -/// of the session object in the Java/Kotlin code. Subsequent calls to other session functions will require -/// this raw pointer to retrieve the [Session] using `Arc::from_raw`. -/// -/// If opening the session fails, an exception is thrown on the JVM, and a null pointer is returned. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class (parameter required by the JNI interface but unused). -/// - `json_config`: Configuration as a JSON string. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNISession_openSessionWithJsonConfigViaJNI( - mut env: JNIEnv, - _class: JClass, - json_config: JString, -) -> *const Session { - let session = open_session_with_json_config(&mut env, json_config); - match session { - Ok(session) => Arc::into_raw(Arc::new(session)), - Err(err) => { - tracing::error!("Unable to open session: {}", err); - throw_exception!(env, zerror!(err)); - null() - } - } -} - -/// Open a Zenoh session with the provided json configuration. -/// -fn open_session_with_json_config(env: &mut JNIEnv, json_config: JString) -> ZResult { - let json_config = decode_string(env, &json_config)?; - let mut deserializer = - json5::Deserializer::from_str(&json_config).map_err(|err| zerror!(err))?; - let config = Config::from_deserializer(&mut deserializer).map_err(|err| match err { - Ok(c) => zerror!("Invalid configuration: {}", c), - Err(e) => zerror!("JSON error: {}", e), - })?; - zenoh::open(config).wait().map_err(|err| zerror!(err)) -} - -/// Open a Zenoh session with a YAML configuration. -/// -/// It returns an [Arc] raw pointer to the Zenoh Session, which should be stored as a private read-only attribute -/// of the session object in the Java/Kotlin code. Subsequent calls to other session functions will require -/// this raw pointer to retrieve the [Session] using `Arc::from_raw`. -/// -/// If opening the session fails, an exception is thrown on the JVM, and a null pointer is returned. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class (parameter required by the JNI interface but unused). -/// - `yaml_config`: Configuration as a YAML string. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNISession_openSessionWithYamlConfigViaJNI( - mut env: JNIEnv, - _class: JClass, - yaml_config: JString, -) -> *const Session { - let session = open_session_with_yaml_config(&mut env, yaml_config); - match session { - Ok(session) => Arc::into_raw(Arc::new(session)), - Err(err) => { - tracing::error!("Unable to open session: {}", err); - throw_exception!(env, zerror!(err)); - null() - } - } -} - -/// Open a Zenoh session with the provided yaml configuration. -/// -fn open_session_with_yaml_config(env: &mut JNIEnv, yaml_config: JString) -> ZResult { - let yaml_config = decode_string(env, &yaml_config)?; - let deserializer = serde_yaml::Deserializer::from_str(&yaml_config); - let config = Config::from_deserializer(deserializer).map_err(|err| match err { - Ok(c) => zerror!("Invalid configuration: {}", c), - Err(e) => zerror!("YAML error: {}", e), - })?; - zenoh::open(config).wait().map_err(|err| zerror!(err)) -} - -/// Closes a Zenoh session via JNI. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `session_ptr`: The raw pointer to the Zenoh session. -/// -/// # Safety: -/// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided session pointer is valid and has not been modified or freed. -/// - The function may throw a JNI exception in case of failure, which should be handled by the caller. -/// - After the session is closed, the provided pointer is no more valid. -/// -#[no_mangle] -#[allow(non_snake_case, unused)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_closeSessionViaJNI( - mut env: JNIEnv, - _class: JClass, - session_ptr: *const Session, -) { - Arc::from_raw(session_ptr); -} - -/// Declare a Zenoh publisher via JNI. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `key_expr_ptr`: Raw pointer to the [KeyExpr] to be used for the publisher, may be null. -/// - `key_expr_str`: String representation of the [KeyExpr] to be used for the publisher. -/// It is only considered when the key_expr_ptr parameter is null, meaning the function is -/// receiving a key expression that was not declared. -/// - `session_ptr`: Raw pointer to the Zenoh [Session] to be used for the publisher. -/// - `congestion_control`: The [zenoh::publisher::CongestionControl] configuration as an ordinal. -/// - `priority`: The [zenoh::core::Priority] configuration as an ordinal. -/// - `is_express`: The express config of the publisher (see [zenoh::prelude::QoSBuilderTrait]). -/// - `reliability`: The reliability value as an ordinal. -/// -/// # Returns: -/// - A raw pointer to the declared Zenoh publisher or null in case of failure. -/// -/// # Safety: -/// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided session pointer is valid and has not been modified or freed. -/// - The ownership of the session is not transferred, and the session pointer remains valid -/// after this function call so it is safe to use it after this call. -/// - The function may throw an exception in case of failure, which should be handled by the caller. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declarePublisherViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - session_ptr: *const Session, - congestion_control: jint, - priority: jint, - is_express: jboolean, - reliability: jint, -) -> *const Publisher<'static> { - let session = Arc::from_raw(session_ptr); - let publisher_ptr = || -> ZResult<*const Publisher<'static>> { - let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; - let congestion_control = decode_congestion_control(congestion_control)?; - let priority = decode_priority(priority)?; - let reliability = decode_reliability(reliability)?; - let result = session - .declare_publisher(key_expr) - .congestion_control(congestion_control) - .priority(priority) - .express(is_express != 0) - .reliability(reliability) - .wait(); - match result { - Ok(publisher) => Ok(Arc::into_raw(Arc::new(publisher))), - Err(err) => Err(zerror!(err)), - } - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }); - std::mem::forget(session); - publisher_ptr -} - -/// Performs a `put` operation in the Zenoh session via JNI. -/// -/// Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `key_expr_ptr`: Raw pointer to the [KeyExpr] to be used for the operation, may be null. -/// - `key_expr_str`: String representation of the [KeyExpr] to be used for the operation. -/// It is only considered when the key_expr_ptr parameter is null, meaning the function is -/// receiving a key expression that was not declared. -/// - `session_ptr`: Raw pointer to the [Session] to be used for the operation. -/// - `payload`: The payload to send through the network. -/// - `encoding_id`: The encoding id of the payload. -/// - `encoding_schema`: Optional encoding schema, may be null. -/// - `congestion_control`: The [CongestionControl] mechanism specified. -/// - `priority`: The [Priority] mechanism specified. -/// - `is_express`: The express flag. -/// - `attachment`: Optional attachment encoded into a byte array. May be null. -/// - `reliability`: The reliability value as an ordinal. -/// -/// Safety: -/// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided session pointer is valid and has not been modified or freed. -/// - The session pointer remains valid and the ownership of the session is not transferred, -/// allowing safe usage of the session after this function call. -/// - The function may throw an exception in case of failure, which should be handled by the Java/Kotlin caller. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_putViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - session_ptr: *const Session, - payload: JByteArray, - encoding_id: jint, - encoding_schema: JString, - congestion_control: jint, - priority: jint, - is_express: jboolean, - attachment: JByteArray, - reliability: jint, -) { - let session = Arc::from_raw(session_ptr); - let _ = || -> ZResult<()> { - let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; - let payload = decode_byte_array(&env, payload)?; - let encoding = decode_encoding(&mut env, encoding_id, &encoding_schema)?; - let congestion_control = decode_congestion_control(congestion_control)?; - let priority = decode_priority(priority)?; - let reliability = decode_reliability(reliability)?; - - let mut put_builder = session - .put(&key_expr, payload) - .congestion_control(congestion_control) - .encoding(encoding) - .express(is_express != 0) - .priority(priority) - .reliability(reliability); - - if !attachment.is_null() { - let attachment = decode_byte_array(&env, attachment)?; - put_builder = put_builder.attachment(attachment) - } - - put_builder - .wait() - .map(|_| tracing::trace!("Put on '{key_expr}'")) - .map_err(|err| zerror!(err)) - }() - .map_err(|err| throw_exception!(env, err)); - std::mem::forget(session); -} - -/// Performs a `delete` operation in the Zenoh session via JNI. -/// -/// Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `key_expr_ptr`: Raw pointer to the [KeyExpr] to be used for the operation, may be null. -/// - `key_expr_str`: String representation of the [KeyExpr] to be used for the operation. -/// It is only considered when the key_expr_ptr parameter is null, meaning the function is -/// receiving a key expression that was not declared. -/// - `session_ptr`: Raw pointer to the [Session] to be used for the operation. -/// - `congestion_control`: The [CongestionControl] mechanism specified. -/// - `priority`: The [Priority] mechanism specified. -/// - `is_express`: The express flag. -/// - `attachment`: Optional attachment encoded into a byte array. May be null. -/// - `reliability`: The reliability value as an ordinal. -/// -/// Safety: -/// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided session pointer is valid and has not been modified or freed. -/// - The session pointer remains valid and the ownership of the session is not transferred, -/// allowing safe usage of the session after this function call. -/// - The function may throw a JNI exception or a Session exception in case of failure, which -/// should be handled by the Java/Kotlin caller. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_deleteViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - session_ptr: *const Session, - congestion_control: jint, - priority: jint, - is_express: jboolean, - attachment: JByteArray, - reliability: jint, -) { - let session = Arc::from_raw(session_ptr); - let _ = || -> ZResult<()> { - let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; - let congestion_control = decode_congestion_control(congestion_control)?; - let priority = decode_priority(priority)?; - let reliability = decode_reliability(reliability)?; - - let mut delete_builder = session - .delete(&key_expr) - .congestion_control(congestion_control) - .express(is_express != 0) - .priority(priority) - .reliability(reliability); - - if !attachment.is_null() { - let attachment = decode_byte_array(&env, attachment)?; - delete_builder = delete_builder.attachment(attachment) - } - - delete_builder - .wait() - .map(|_| tracing::trace!("Delete on '{key_expr}'")) - .map_err(|err| zerror!(err)) - }() - .map_err(|err| throw_exception!(env, err)); - std::mem::forget(session); -} - -/// Declare a Zenoh subscriber via JNI. -/// -/// Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `key_expr_ptr`: The key expression pointer for the subscriber. May be null in case of using an -/// undeclared key expression. -/// - `key_expr_str`: String representation of the key expression to be used to declare the subscriber. -/// It won't be considered in case a key_expr_ptr to a declared key expression is provided. -/// - `session_ptr`: The raw pointer to the Zenoh session. -/// - `callback`: The callback function as an instance of the `JNISubscriberCallback` interface in Java/Kotlin. -/// - `on_close`: A Java/Kotlin `JNIOnCloseCallback` function interface to be called upon closing the subscriber. -/// -/// Returns: -/// - A raw pointer to the declared Zenoh subscriber. In case of failure, an exception is thrown and null is returned. -/// -/// Safety: -/// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided session pointer is valid and has not been modified or freed. -/// - The session pointer remains valid and the ownership of the session is not transferred, -/// allowing safe usage of the session after this function call. -/// - The callback function passed as `callback` must be a valid instance of the `JNISubscriberCallback` interface -/// in Java/Kotlin, matching the specified signature. -/// - The function may throw a JNI exception in case of failure, which should be handled by the caller. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareSubscriberViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - session_ptr: *const Session, - callback: JObject, - on_close: JObject, -) -> *const Subscriber<()> { - let session = Arc::from_raw(session_ptr); - || -> ZResult<*const Subscriber<()>> { - let java_vm = Arc::new(get_java_vm(&mut env)?); - let callback_global_ref = get_callback_global_ref(&mut env, callback)?; - let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; - let on_close = load_on_close(&java_vm, on_close_global_ref); - - let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; - tracing::debug!("Declaring subscriber on '{}'...", key_expr); - - let result = session - .declare_subscriber(key_expr.to_owned()) - .callback(move |sample: Sample| { - on_close.noop(); // Moves `on_close` inside the closure so it gets destroyed with the closure - let _ = || -> ZResult<()> { - let mut env = java_vm.attach_current_thread_as_daemon().map_err(|err| { - zerror!("Unable to attach thread for subscriber: {}", err) - })?; - let byte_array = bytes_to_java_array(&env, sample.payload()) - .map(|array| env.auto_local(array))?; - - let encoding_id: jint = sample.encoding().id() as jint; - let encoding_schema = match sample.encoding().schema() { - Some(schema) => slice_to_java_string(&env, schema)?, - None => JString::default(), - }; - let kind = sample.kind() as jint; - let (timestamp, is_valid) = sample - .timestamp() - .map(|timestamp| (timestamp.get_time().as_u64(), true)) - .unwrap_or((0, false)); - - let attachment_bytes = sample - .attachment() - .map_or_else( - || Ok(JByteArray::default()), - |attachment| bytes_to_java_array(&env, attachment), - ) - .map(|array| env.auto_local(array)) - .map_err(|err| zerror!("Error processing attachment: {}", err))?; - - let key_expr_str = env.auto_local( - env.new_string(sample.key_expr().to_string()) - .map_err(|err| zerror!("Error processing sample key expr: {}", err))?, - ); - - let express = sample.express(); - let priority = sample.priority() as jint; - let cc = sample.congestion_control() as jint; - - env.call_method( - &callback_global_ref, - "run", - "(Ljava/lang/String;[BILjava/lang/String;IJZ[BZII)V", - &[ - JValue::from(&key_expr_str), - JValue::from(&byte_array), - JValue::from(encoding_id), - JValue::from(&encoding_schema), - JValue::from(kind), - JValue::from(timestamp as i64), - JValue::from(is_valid), - JValue::from(&attachment_bytes), - JValue::from(express), - JValue::from(priority), - JValue::from(cc), - ], - ) - .map_err(|err| zerror!(err))?; - Ok(()) - }() - .map_err(|err| tracing::error!("On subscriber callback error: {err}")); - }) - .wait(); - - let subscriber = result.map_err(|err| zerror!("Unable to declare subscriber: {}", err))?; - - tracing::debug!("Subscriber declared on '{}'.", key_expr); - std::mem::forget(session); - Ok(Arc::into_raw(Arc::new(subscriber))) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }) -} - -/// Declare a Zenoh querier via JNI. -/// -/// This function is meant to be called from Java/Kotlin code through JNI. -/// -/// Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `key_expr_ptr`: A raw pointer to the [KeyExpr] to be used for the querier. May be null in case of using an -/// undeclared key expression. -/// - `key_expr_str`: String representation of the key expression to be used to declare the querier. -/// It won't be considered in case a key_expr_ptr to a declared key expression is provided. -/// - `target`: The ordinal value of the query target enum value. -/// - `consolidation`: The ordinal value of the consolidation enum value. -/// - `congestion_control`: The ordinal value of the congestion control enum value. -/// - `priority`: The ordinal value of the priority enum value. -/// - `is_express`: The boolean express value of the QoS provided. -/// - `timeout_ms`: The timeout in milliseconds. -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareQuerierViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - session_ptr: *const Session, - target: jint, - consolidation: jint, - congestion_control: jint, - priority: jint, - is_express: jboolean, - timeout_ms: jlong, - accept_replies: jint, -) -> *const Querier<'static> { - let session = Arc::from_raw(session_ptr); - || -> ZResult<*const Querier<'static>> { - let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; - let query_target = decode_query_target(target)?; - let consolidation = decode_consolidation(consolidation)?; - let congestion_control = decode_congestion_control(congestion_control)?; - let timeout = Duration::from_millis(timeout_ms as u64); - let priority = decode_priority(priority)?; - let reply_key_expr = decode_reply_key_expr(accept_replies)?; - tracing::debug!("Declaring querier on '{}'...", key_expr); - - let querier = session - .declare_querier(key_expr.to_owned()) - .congestion_control(congestion_control) - .consolidation(consolidation) - .express(is_express != 0) - .target(query_target) - .priority(priority) - .timeout(timeout) - .accept_replies(reply_key_expr) - .wait() - .map_err(|err| zerror!(err))?; - - tracing::debug!("Querier declared on '{}'.", key_expr); - std::mem::forget(session); - Ok(Arc::into_raw(Arc::new(querier))) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }) -} - -/// Declare a Zenoh queryable via JNI. -/// -/// This function is meant to be called from Java/Kotlin code through JNI. -/// -/// Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `key_expr_ptr`: A raw pointer to the [KeyExpr] to be used for the queryable. May be null in case of using an -/// undeclared key expression. -/// - `key_expr_str`: String representation of the key expression to be used to declare the queryable. -/// It won't be considered in case a key_expr_ptr to a declared key expression is provided. -/// - `session_ptr`: A raw pointer to the Zenoh [Session] to be used to declare the queryable. -/// - `callback`: The callback function as an instance of the `JNIQueryableCallback` interface in Java/Kotlin. -/// - `on_close`: A Java/Kotlin `JNIOnCloseCallback` function interface to be called upon closing the queryable. -/// - `complete`: The completeness of the queryable. -/// -/// Returns: -/// - A raw pointer to the declared Zenoh queryable. In case of failure, an exception is thrown and null is returned. -/// -/// Safety: -/// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided session pointer is valid and has not been modified or freed. -/// - The session pointer remains valid and the ownership of the session is not transferred, -/// allowing safe usage of the session after this function call. -/// - The callback function passed as `callback` must be a valid instance of the `JNIQueryableCallback` interface -/// in Java/Kotlin, matching the specified signature. -/// - The function may throw a JNI exception in case of failure, which should be handled by the caller. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareQueryableViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - session_ptr: *const Session, - callback: JObject, - on_close: JObject, - complete: jboolean, -) -> *const Queryable<()> { - let session = Arc::from_raw(session_ptr); - let query_ptr = || -> ZResult<*const Queryable<()>> { - let java_vm = Arc::new(get_java_vm(&mut env)?); - let callback_global_ref = get_callback_global_ref(&mut env, callback)?; - let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; - let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; - let complete = complete != 0; - let on_close = load_on_close(&java_vm, on_close_global_ref); - tracing::debug!("Declaring queryable through JNI on {}", key_expr); - let builder = session - .declare_queryable(key_expr) - .callback(move |query: Query| { - on_close.noop(); // Does nothing, but moves `on_close` inside the closure so it gets destroyed with the closure - let env = match java_vm.attach_current_thread_as_daemon() { - Ok(env) => env, - Err(err) => { - tracing::error!("Unable to attach thread for queryable callback: {}", err); - return; - } - }; - - tracing::debug!("Receiving query through JNI: {}", query.to_string()); - match on_query(env, query, &callback_global_ref) { - Ok(_) => tracing::debug!("Queryable callback called successfully."), - Err(err) => tracing::error!("Error calling queryable callback: {}", err), - } - }) - .complete(complete); - - let queryable = builder - .wait() - .map_err(|err| zerror!("Error declaring queryable: {}", err))?; - Ok(Arc::into_raw(Arc::new(queryable))) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }); - std::mem::forget(session); - query_ptr -} - -fn on_query(mut env: JNIEnv, query: Query, callback_global_ref: &GlobalRef) -> ZResult<()> { - let selector_params_jstr = env - .new_string(query.parameters().to_string()) - .map(|value| env.auto_local(value)) - .map_err(|err| { - zerror!( - "Could not create a JString through JNI for the Query key expression. {}", - err - ) - })?; - - let (payload, encoding_id, encoding_schema) = if let Some(payload) = query.payload() { - let encoding = query.encoding().unwrap(); //If there is payload, there is encoding. - let encoding_id = encoding.id() as jint; - let encoding_schema = encoding - .schema() - .map_or_else( - || Ok(JString::default()), - |schema| slice_to_java_string(&env, schema), - ) - .map(|value| env.auto_local(value))?; - let byte_array = bytes_to_java_array(&env, payload).map(|value| env.auto_local(value))?; - (byte_array, encoding_id, encoding_schema) - } else { - ( - env.auto_local(JByteArray::default()), - 0, - env.auto_local(JString::default()), - ) - }; - - let attachment_bytes = query - .attachment() - .map_or_else( - || Ok(JByteArray::default()), - |attachment| bytes_to_java_array(&env, attachment), - ) - .map(|value| env.auto_local(value)) - .map_err(|err| zerror!("Error processing attachment of reply: {}.", err))?; - - let key_expr_str = env - .new_string(query.key_expr().to_string()) - .map(|key_expr| env.auto_local(key_expr)) - .map_err(|err| { - zerror!( - "Could not create a JString through JNI for the Query key expression: {}.", - err - ) - })?; - - let accepts_replies: jint = match query.accepts_replies() { - ReplyKeyExpr::MatchingQuery => 0, - ReplyKeyExpr::Any => 1, - }; - - let query_ptr = Arc::into_raw(Arc::new(query)); - - let result = env - .call_method( - callback_global_ref, - "run", - "(Ljava/lang/String;Ljava/lang/String;[BILjava/lang/String;[BJI)V", - &[ - JValue::from(&key_expr_str), - JValue::from(&selector_params_jstr), - JValue::from(&payload), - JValue::from(encoding_id), - JValue::from(&encoding_schema), - JValue::from(&attachment_bytes), - JValue::from(query_ptr as jlong), - JValue::from(accepts_replies), - ], - ) - .map(|_| ()) - .map_err(|err| { - // The callback could not be invoked, therefore the created kotlin query object won't be - // used. Since `query_ptr` as well as `key_expr_ptr` was created within this function - // and remains unaltered, it is safe to reclaim ownership of the memory by converting - // the raw pointers back into an `Arc` and freeing the memory. - unsafe { - Arc::from_raw(query_ptr); - }; - _ = env.exception_describe(); - zerror!(err) - }); - result -} - -/// Declare a [KeyExpr] through a [Session] via JNI. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `session_ptr`: A raw pointer to the Zenoh [Session] from which to declare the key expression. -/// - `key_expr_str`: A Java String with the intended key expression. -/// -/// # Returns: -/// - A raw pointer to the declared key expression. In case of failure, an exception is thrown and null is returned. -/// -/// # Safety: -/// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided session pointer is valid and has not been modified or freed. -/// - The session pointer remains valid and the ownership of the session is not transferred, -/// allowing safe usage of the session after this function call. -/// - The function may throw an exception in case of failure, which should be handled by the caller. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_declareKeyExprViaJNI( - mut env: JNIEnv, - _class: JClass, - session_ptr: *const Session, - key_expr_str: JString, -) -> *const KeyExpr<'static> { - let session: Arc = Arc::from_raw(session_ptr); - let key_expr_ptr = || -> ZResult<*const KeyExpr<'static>> { - let key_expr_str = decode_string(&mut env, &key_expr_str)?; - let key_expr = session - .declare_keyexpr(key_expr_str.to_owned()) - .wait() - .map_err(|err| { - zerror!( - "Unable to declare key expression '{}': {}", - key_expr_str, - err - ) - })?; - Ok(Arc::into_raw(Arc::new(key_expr))) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - null() - }); - mem::forget(session); - key_expr_ptr -} - -/// Undeclare a [KeyExpr] through a [Session] via JNI. -/// -/// The key expression must have been previously declared on the specified session, otherwise an -/// exception is thrown. -/// -/// This functions frees the key expression pointer provided. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `session_ptr`: A raw pointer to the Zenoh [Session] from which to undeclare the key expression. -/// - `key_expr_ptr`: A raw pointer to the [KeyExpr] to undeclare. -/// -/// # Safety: -/// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided session and keyexpr pointers are valid and have not been modified or freed. -/// - The session pointer remains valid after this function call. -/// - The key expression pointer is voided after this function call. -/// - The function may throw an exception in case of failure, which should be handled by the caller. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_undeclareKeyExprViaJNI( - mut env: JNIEnv, - _class: JClass, - session_ptr: *const Session, - key_expr_ptr: *const KeyExpr<'static>, -) { - let session = Arc::from_raw(session_ptr); - let key_expr = Arc::from_raw(key_expr_ptr); - let key_expr_clone = key_expr.deref().clone(); - match session.undeclare(key_expr_clone).wait() { - Ok(_) => {} - Err(err) => { - throw_exception!( - env, - zerror!("Unable to declare key expression '{}': {}", key_expr, err) - ); - } - } - std::mem::forget(session); - // `key_expr` is intentionally left to be freed by Rust -} - -/// Performs a `get` operation in the Zenoh session via JNI with Value. -/// -/// # Parameters: -/// - `env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `key_expr_ptr`: Raw pointer to a declared [KeyExpr] to be used for the query. May be null in case -/// of using a non declared key expression, in which case the `key_expr_str` parameter will be used instead. -/// - `key_expr_str`: String representation of the key expression to be used to declare the query. It is not -/// considered if a `key_expr_ptr` is provided. -/// - `selector_params`: Optional parameters of the selector. -/// - `session_ptr`: A raw pointer to the Zenoh [Session]. -/// - `callback`: A Java/Kotlin callback to be called upon receiving a reply. -/// - `on_close`: A Java/Kotlin `JNIOnCloseCallback` function interface to be called when no more replies will be received. -/// - `timeout_ms`: The timeout in milliseconds. -/// - `target`: The query target as the ordinal of the enum. -/// - `consolidation`: The consolidation mode as the ordinal of the enum. -/// - `attachment`: An optional attachment encoded into a byte array. -/// - `payload`: Optional payload for the query. -/// - `encoding_id`: The encoding of the payload. -/// - `encoding_schema`: The encoding schema of the payload, may be null. -/// - `congestion_control`: The ordinal value of the congestion control enum value. -/// - `priority`: The ordinal value of the priority enum value. -/// - `is_express`: The boolean express value of the QoS provided. -/// -/// Safety: -/// - The function is marked as unsafe due to raw pointer manipulation and JNI interaction. -/// - It assumes that the provided session pointer is valid and has not been modified or freed. -/// - The session pointer remains valid and the ownership of the session is not transferred, -/// allowing safe usage of the session after this function call. -/// - The function may throw a JNI exception in case of failure, which should be handled by the caller. -/// -/// Throws: -/// - An exception in case of failure handling the query. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getViaJNI( - mut env: JNIEnv, - _class: JClass, - key_expr_ptr: /*nullable*/ *const KeyExpr<'static>, - key_expr_str: JString, - selector_params: /*nullable*/ JString, - session_ptr: *const Session, - callback: JObject, - on_close: JObject, - timeout_ms: jlong, - target: jint, - consolidation: jint, - attachment: /*nullable*/ JByteArray, - payload: /*nullable*/ JByteArray, - encoding_id: jint, - encoding_schema: /*nullable*/ JString, - congestion_control: jint, - priority: jint, - is_express: jboolean, - accept_replies: jint, -) { - let session = Arc::from_raw(session_ptr); - let _ = || -> ZResult<()> { - let key_expr = process_kotlin_key_expr(&mut env, &key_expr_str, key_expr_ptr)?; - let java_vm = Arc::new(get_java_vm(&mut env)?); - let callback_global_ref = get_callback_global_ref(&mut env, callback)?; - let on_close_global_ref = get_callback_global_ref(&mut env, on_close)?; - let query_target = decode_query_target(target)?; - let consolidation = decode_consolidation(consolidation)?; - let timeout = Duration::from_millis(timeout_ms as u64); - let congestion_control = decode_congestion_control(congestion_control)?; - let priority = decode_priority(priority)?; - let reply_key_expr = decode_reply_key_expr(accept_replies)?; - let on_close = load_on_close(&java_vm, on_close_global_ref); - let selector_params = if selector_params.is_null() { - String::new() - } else { - decode_string(&mut env, &selector_params)? - }; - let selector = Selector::owned(&key_expr, selector_params); - let mut get_builder = session - .get(selector) - .congestion_control(congestion_control) - .priority(priority) - .express(is_express != 0) - .callback(move |reply| { - || -> ZResult<()> { - on_close.noop(); // Does nothing, but moves `on_close` inside the closure so it gets destroyed with the closure - tracing::debug!("Receiving reply through JNI: {:?}", reply); - let mut env = java_vm.attach_current_thread_as_daemon().map_err(|err| { - zerror!("Unable to attach thread for GET query callback: {}.", err) - })?; - - match reply.result() { - Ok(sample) => on_reply_success( - &mut env, - reply.replier_id(), - sample, - &callback_global_ref, - ), - Err(error) => on_reply_error( - &mut env, - reply.replier_id(), - error, - &callback_global_ref, - ), - } - }() - .unwrap_or_else(|err| tracing::error!("Error on get callback: {err}")); - }) - .target(query_target) - .timeout(timeout) - .consolidation(consolidation) - .accept_replies(reply_key_expr); - - if !payload.is_null() { - let encoding = decode_encoding(&mut env, encoding_id, &encoding_schema)?; - get_builder = get_builder.encoding(encoding); - get_builder = get_builder.payload(decode_byte_array(&env, payload)?); - } - - if !attachment.is_null() { - let attachment = decode_byte_array(&env, attachment)?; - get_builder = get_builder.attachment::>(attachment); - } - - get_builder - .wait() - .map(|_| tracing::trace!("Performing get on '{key_expr}'.",)) - .map_err(|err| zerror!(err)) - }() - .map_err(|err| throw_exception!(env, err)); - std::mem::forget(session); -} - -pub(crate) fn on_reply_success( - env: &mut JNIEnv, - replier_id: Option, - sample: &Sample, - callback_global_ref: &GlobalRef, -) -> ZResult<()> { - let zenoh_id = replier_id - .map_or_else( - || Ok(JByteArray::default()), - |replier_id| { - env.byte_array_from_slice(&replier_id.zid().to_le_bytes()) - .map_err(|err| zerror!(err)) - }, - ) - .map(|value| env.auto_local(value))?; - let eid = replier_id.map_or_else(|| 0, |replier_id| replier_id.eid() as jint); - - let byte_array = - bytes_to_java_array(env, sample.payload()).map(|value| env.auto_local(value))?; - let encoding: jint = sample.encoding().id() as jint; - let encoding_schema = sample - .encoding() - .schema() - .map_or_else( - || Ok(JString::default()), - |schema| slice_to_java_string(env, schema), - ) - .map(|value| env.auto_local(value))?; - let kind = sample.kind() as jint; - - let (timestamp, is_valid) = sample - .timestamp() - .map(|timestamp| (timestamp.get_time().as_u64(), true)) - .unwrap_or((0, false)); - - let attachment_bytes = sample - .attachment() - .map_or_else( - || Ok(JByteArray::default()), - |attachment| bytes_to_java_array(env, attachment), - ) - .map(|value| env.auto_local(value)) - .map_err(|err| zerror!("Error processing attachment of reply: {}.", err))?; - - let key_expr_str = env - .new_string(sample.key_expr().to_string()) - .map(|value| env.auto_local(value)) - .map_err(|err| { - zerror!( - "Could not create a JString through JNI for the Sample key expression. {}", - err - ) - })?; - - let express = sample.express(); - let priority = sample.priority() as jint; - let cc = sample.congestion_control() as jint; - - let result = match env.call_method( - callback_global_ref, - "run", - "([BIZLjava/lang/String;[BILjava/lang/String;IJZ[BZII)V", - &[ - JValue::from(&zenoh_id), - JValue::from(eid), - JValue::from(true), - JValue::from(&key_expr_str), - JValue::from(&byte_array), - JValue::from(encoding), - JValue::from(&encoding_schema), - JValue::from(kind), - JValue::from(timestamp as i64), - JValue::from(is_valid), - JValue::from(&attachment_bytes), - JValue::from(express), - JValue::from(priority), - JValue::from(cc), - ], - ) { - Ok(_) => Ok(()), - Err(err) => { - _ = env.exception_describe(); - Err(zerror!("On GET callback error: {}", err)) - } - }; - result -} - -pub(crate) fn on_reply_error( - env: &mut JNIEnv, - replier_id: Option, - reply_error: &ReplyError, - callback_global_ref: &GlobalRef, -) -> ZResult<()> { - let zenoh_id = replier_id - .map_or_else( - || Ok(JByteArray::default()), - |replier_id| { - env.byte_array_from_slice(&replier_id.zid().to_le_bytes()) - .map_err(|err| zerror!(err)) - }, - ) - .map(|value| env.auto_local(value))?; - let eid = replier_id.map_or_else(|| 0, |replier_id| replier_id.eid() as jint); - - let payload = - bytes_to_java_array(env, reply_error.payload()).map(|value| env.auto_local(value))?; - let encoding_id: jint = reply_error.encoding().id() as jint; - let encoding_schema = reply_error - .encoding() - .schema() - .map_or_else( - || Ok(JString::default()), - |schema| slice_to_java_string(env, schema), - ) - .map(|value| env.auto_local(value))?; - let result = match env.call_method( - callback_global_ref, - "run", - "([BIZLjava/lang/String;[BILjava/lang/String;IJZ[BZII)V", - &[ - JValue::from(&zenoh_id), - JValue::from(eid), - JValue::from(false), - JValue::from(&JString::default()), - JValue::from(&payload), - JValue::from(encoding_id), - JValue::from(&encoding_schema), - // The remaining parameters aren't used in case of replying error, so we set them to default. - JValue::from(0 as jint), - JValue::from(0_i64), - JValue::from(false), - JValue::from(&JByteArray::default()), - JValue::from(false), - JValue::from(0 as jint), - JValue::from(0 as jint), - ], - ) { - Ok(_) => Ok(()), - Err(err) => { - _ = env.exception_describe(); - Err(zerror!("On GET callback error: {}", err)) - } - }; - result -} - -/// Returns a list of zenoh ids as byte arrays corresponding to the peers connected to the session provided. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getPeersZidViaJNI( - mut env: JNIEnv, - _class: JClass, - session_ptr: *const Session, -) -> jobject { - let session = Arc::from_raw(session_ptr); - let ids = { - let peers_zid = session.info().peers_zid().wait(); - let ids = peers_zid.collect::>(); - ids_to_java_list(&mut env, ids).map_err(|err| zerror!(err)) - } - .unwrap_or_else(|err| { - throw_exception!(env, err); - JObject::default().as_raw() - }); - std::mem::forget(session); - ids -} - -/// Returns a list of zenoh ids as byte arrays corresponding to the routers connected to the session provided. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getRoutersZidViaJNI( - mut env: JNIEnv, - _class: JClass, - session_ptr: *const Session, -) -> jobject { - let session = Arc::from_raw(session_ptr); - let ids = { - let peers_zid = session.info().routers_zid().wait(); - let ids = peers_zid.collect::>(); - ids_to_java_list(&mut env, ids).map_err(|err| zerror!(err)) - } - .unwrap_or_else(|err| { - throw_exception!(env, err); - JObject::default().as_raw() - }); - std::mem::forget(session); - ids -} - -/// Returns the Zenoh ID as a byte array of the session. -#[no_mangle] -#[allow(non_snake_case)] -pub unsafe extern "C" fn Java_io_zenoh_jni_JNISession_getZidViaJNI( - mut env: JNIEnv, - _class: JClass, - session_ptr: *const Session, -) -> jbyteArray { - let session = Arc::from_raw(session_ptr); - let ids = { - let zid = session.info().zid().wait(); - env.byte_array_from_slice(&zid.to_le_bytes()) - .map(|x| x.as_raw()) - .map_err(|err| zerror!(err)) - } - .unwrap_or_else(|err| { - throw_exception!(env, err); - JByteArray::default().as_raw() - }); - std::mem::forget(session); - ids -} - -fn ids_to_java_list(env: &mut JNIEnv, ids: Vec) -> jni::errors::Result { - let array_list = env.new_object("java/util/ArrayList", "()V", &[])?; - let jlist = JList::from_env(env, &array_list)?; - for id in ids { - let value = &mut env.byte_array_from_slice(&id.to_le_bytes())?; - jlist.add(env, value)?; - } - Ok(array_list.as_raw()) -} diff --git a/zenoh-jni/src/subscriber.rs b/zenoh-jni/src/subscriber.rs deleted file mode 100644 index 3462ec7e..00000000 --- a/zenoh-jni/src/subscriber.rs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::sync::Arc; - -use jni::{objects::JClass, JNIEnv}; -use zenoh::pubsub::Subscriber; - -/// Frees the [Subscriber]. -/// -/// # Parameters: -/// - `_env`: The JNI environment. -/// - `_class`: The JNI class. -/// - `subscriber_ptr`: The raw pointer to the Zenoh subscriber ([Subscriber]). -/// -/// # Safety: -/// - The function is marked as unsafe due to raw pointer manipulation. -/// - It assumes that the provided subscriber pointer is valid and has not been modified or freed. -/// - The function takes ownership of the raw pointer and releases the associated memory. -/// - After calling this function, the subscriber pointer becomes invalid and should not be used anymore. -/// -#[no_mangle] -#[allow(non_snake_case)] -pub(crate) unsafe extern "C" fn Java_io_zenoh_jni_JNISubscriber_freePtrViaJNI( - _env: JNIEnv, - _: JClass, - subscriber_ptr: *const Subscriber<()>, -) { - Arc::from_raw(subscriber_ptr); -} diff --git a/zenoh-jni/src/utils.rs b/zenoh-jni/src/utils.rs deleted file mode 100644 index a2c6a9f4..00000000 --- a/zenoh-jni/src/utils.rs +++ /dev/null @@ -1,189 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use std::sync::Arc; - -use crate::{errors::ZResult, throw_exception, zerror}; -use jni::{ - objects::{JByteArray, JObject, JString}, - sys::jint, - JNIEnv, JavaVM, -}; -use zenoh::{ - bytes::{Encoding, ZBytes}, - internal::buffers::ZSlice, - qos::{CongestionControl, Priority, Reliability}, - query::{ConsolidationMode, QueryTarget, ReplyKeyExpr}, -}; - -/// Converts a JString into a rust String. -pub(crate) fn decode_string(env: &mut JNIEnv, string: &JString) -> ZResult { - let binding = env - .get_string(string) - .map_err(|err| zerror!("Error while retrieving JString: {}", err))?; - let value = binding - .to_str() - .map_err(|err| zerror!("Error decoding JString: {}", err))?; - Ok(value.to_string()) -} - -pub(crate) fn decode_encoding( - env: &mut JNIEnv, - encoding: jint, - schema: &JString, -) -> ZResult { - let schema: Option = if schema.is_null() { - None - } else { - Some(decode_string(env, schema)?.into_bytes().into()) - }; - let encoding_id = - u16::try_from(encoding).map_err(|err| zerror!("Failed to decode encoding: {}", err))?; - Ok(Encoding::new(encoding_id, schema)) -} - -pub(crate) fn get_java_vm(env: &mut JNIEnv) -> ZResult { - env.get_java_vm() - .map_err(|err| zerror!("Unable to retrieve JVM reference: {}", err)) -} - -pub(crate) fn get_callback_global_ref( - env: &mut JNIEnv, - callback: JObject, -) -> crate::errors::ZResult { - env.new_global_ref(callback) - .map_err(|err| zerror!("Unable to get reference to the provided callback: {}", err)) -} - -/// Helper function to convert a JByteArray into a Vec. -pub(crate) fn decode_byte_array(env: &JNIEnv<'_>, payload: JByteArray) -> ZResult> { - let payload_len = env - .get_array_length(&payload) - .map(|length| length as usize) - .map_err(|err| zerror!(err))?; - let mut buff = vec![0; payload_len]; - env.get_byte_array_region(payload, 0, &mut buff[..]) - .map_err(|err| zerror!(err))?; - let buff: Vec = unsafe { std::mem::transmute::, Vec>(buff) }; - Ok(buff) -} - -pub(crate) fn decode_priority(priority: jint) -> ZResult { - Priority::try_from(priority as u8).map_err(|err| zerror!("Error retrieving priority: {}.", err)) -} - -pub(crate) fn decode_congestion_control(congestion_control: jint) -> ZResult { - match congestion_control { - 1 => Ok(CongestionControl::Block), - 0 => Ok(CongestionControl::Drop), - value => Err(zerror!("Unknown congestion control '{}'.", value)), - } -} - -pub(crate) fn decode_query_target(target: jint) -> ZResult { - match target { - 0 => Ok(QueryTarget::BestMatching), - 1 => Ok(QueryTarget::All), - 2 => Ok(QueryTarget::AllComplete), - value => Err(zerror!("Unable to decode QueryTarget '{}'.", value)), - } -} - -pub(crate) fn decode_reply_key_expr(reply_key_expr: jint) -> ZResult { - match reply_key_expr { - 0 => Ok(ReplyKeyExpr::MatchingQuery), - 1 => Ok(ReplyKeyExpr::Any), - value => Err(zerror!("Unable to decode ReplyKeyExpr '{}'.", value)), - } -} - -pub(crate) fn decode_consolidation(consolidation: jint) -> ZResult { - match consolidation { - 0 => Ok(ConsolidationMode::Auto), - 1 => Ok(ConsolidationMode::None), - 2 => Ok(ConsolidationMode::Monotonic), - 3 => Ok(ConsolidationMode::Latest), - value => Err(zerror!("Unable to decode consolidation '{}'", value)), - } -} - -pub(crate) fn decode_reliability(reliability: jint) -> ZResult { - match reliability { - 0 => Ok(Reliability::BestEffort), - 1 => Ok(Reliability::Reliable), - value => Err(zerror!("Unable to decode reliability '{}'", value)), - } -} - -pub(crate) fn bytes_to_java_array<'a>(env: &JNIEnv<'a>, slice: &ZBytes) -> ZResult> { - env.byte_array_from_slice(&slice.to_bytes()) - .map_err(|err| zerror!(err)) -} - -pub(crate) fn slice_to_java_string<'a>(env: &JNIEnv<'a>, slice: &ZSlice) -> ZResult> { - env.new_string( - String::from_utf8(slice.to_vec()) - .map_err(|err| zerror!("Unable to decode string: {}", err))?, - ) - .map_err(|err| zerror!(err)) -} - -/// A type that calls a function when dropped -pub(crate) struct CallOnDrop(core::mem::MaybeUninit); -impl CallOnDrop { - /// Constructs a value that calls `f` when dropped. - pub fn new(f: F) -> Self { - Self(core::mem::MaybeUninit::new(f)) - } - /// Does nothing, but tricks closures into moving the value inside, - /// so that the closure's destructor will call `drop(self)`. - pub fn noop(&self) {} -} -impl Drop for CallOnDrop { - fn drop(&mut self) { - // Take ownership of the closure that is always initialized, - // since the only constructor uses `MaybeUninit::new` - let f = unsafe { self.0.assume_init_read() }; - // Call the now owned function - f(); - } -} - -pub(crate) fn load_on_close( - java_vm: &Arc, - on_close_global_ref: jni::objects::GlobalRef, -) -> CallOnDrop { - CallOnDrop::new({ - let java_vm = java_vm.clone(); - move || { - let mut env = match java_vm.attach_current_thread_as_daemon() { - Ok(env) => env, - Err(err) => { - tracing::error!("Unable to attach thread for 'onClose' callback: {}", err); - return; - } - }; - match env.call_method(on_close_global_ref, "run", "()V", &[]) { - Ok(_) => (), - Err(err) => { - _ = env.exception_describe(); - throw_exception!( - env, - zerror!("Error while running 'onClose' callback: {}", err) - ); - } - } - } - }) -} diff --git a/zenoh-jni/src/zenoh_id.rs b/zenoh-jni/src/zenoh_id.rs deleted file mode 100644 index 6647f86f..00000000 --- a/zenoh-jni/src/zenoh_id.rs +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright (c) 2023 ZettaScale Technology -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ZettaScale Zenoh Team, -// - -use crate::{errors::ZResult, throw_exception, utils::decode_byte_array, zerror}; -use jni::{ - objects::{JByteArray, JClass, JString}, - sys::jstring, - JNIEnv, -}; -use zenoh::session::ZenohId; - -/// Returns the string representation of a ZenohID. -#[no_mangle] -#[allow(non_snake_case)] -pub extern "C" fn Java_io_zenoh_jni_JNIZenohId_toStringViaJNI( - mut env: JNIEnv, - _class: JClass, - zenoh_id: JByteArray, -) -> jstring { - || -> ZResult { - let bytes = decode_byte_array(&env, zenoh_id)?; - let zenohid = ZenohId::try_from(bytes.as_slice()).map_err(|err| zerror!(err))?; - env.new_string(zenohid.to_string()) - .map_err(|err| zerror!(err)) - }() - .unwrap_or_else(|err| { - throw_exception!(env, err); - JString::default() - }) - .as_raw() -}