Skip to content

Commit b6b8cb2

Browse files
committed
reuse JNINative
1 parent 4491485 commit b6b8cb2

17 files changed

Lines changed: 389 additions & 383 deletions

prebindgen-ext/src/jni/jni_kotlin_ext.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,11 @@ import kotlin.concurrent.write
295295
* destructor entry points without a matching `#[prebindgen]` fn use
296296
* [close]. The auto-generated wrappers in `JNIWrappers.kt` are the
297297
* only callers that need to know which mode applies.
298+
*
299+
* Marked `open` so the hand-maintained `JNI*.kt` typed-handle classes
300+
* can subclass for type safety while inheriting the lock contract.
298301
*/
299-
public class NativeHandle(initial: Long) {
302+
public open class NativeHandle(initial: Long) {
300303
private val lock = ReentrantReadWriteLock()
301304
302305
/** Volatile so [peek] is atomic on 32-bit JVMs and observes the
@@ -410,7 +413,21 @@ fn render_jni_wrappers_source(
410413
out.push_str(&format!("import {}\n", imp));
411414
}
412415
out.push('\n');
413-
out.push_str(&body);
416+
// Wrap the wrappers in an `object` so the names don't collide with
417+
// same-named methods on the hand-maintained JNI*.kt classes
418+
// (`put`, `delete`, `close`, etc.). Callers use `JNIWrappers.put(...)`.
419+
out.push_str("public object JNIWrappers {\n");
420+
// Indent each emitted wrapper body by 4 spaces.
421+
for line in body.lines() {
422+
if line.is_empty() {
423+
out.push('\n');
424+
} else {
425+
out.push_str(" ");
426+
out.push_str(line);
427+
out.push('\n');
428+
}
429+
}
430+
out.push_str("}\n");
414431
out
415432
}
416433

zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIAdvancedPublisher.kt

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,31 @@ import io.zenoh.exceptions.ZError
1818
import io.zenoh.jni.callbacks.JNIMatchingListenerCallback
1919
import io.zenoh.jni.callbacks.JNIOnCloseCallback
2020

21-
/**
22-
* Adapter class for a native Zenoh AdvancedPublisher.
23-
*
24-
* @param initialPtr Raw pointer to the underlying native AdvancedPublisher.
25-
*/
26-
public class JNIAdvancedPublisher(initialPtr: Long) {
27-
private val handle = NativeHandle(initialPtr)
21+
/** Typed [NativeHandle] for a native Zenoh `AdvancedPublisher`. */
22+
public class JNIAdvancedPublisher(initialPtr: Long) : NativeHandle(initialPtr) {
2823

2924
@Throws(ZError::class)
30-
fun put(payload: ByteArray, encoding: JNIEncoding, attachment: ByteArray?) = handle.withPtr { ptr ->
25+
fun put(payload: ByteArray, encoding: JNIEncoding, attachment: ByteArray?) = withPtr { ptr ->
3126
putViaJNI(ptr, payload, encoding, attachment)
3227
}
3328

3429
@Throws(ZError::class)
35-
fun delete(attachment: ByteArray?) = handle.withPtr { ptr ->
30+
fun delete(attachment: ByteArray?) = withPtr { ptr ->
3631
deleteViaJNI(ptr, attachment)
3732
}
3833

3934
@Throws(ZError::class)
4035
fun declareMatchingListener(callback: JNIMatchingListenerCallback, onClose: JNIOnCloseCallback): JNIMatchingListener =
41-
handle.withPtr { ptr -> JNIMatchingListener(declareMatchingListenerViaJNI(ptr, callback, onClose)) }
36+
withPtr { ptr -> JNIMatchingListener(declareMatchingListenerViaJNI(ptr, callback, onClose)) }
4237

4338
@Throws(ZError::class)
4439
fun declareBackgroundMatchingListener(callback: JNIMatchingListenerCallback, onClose: JNIOnCloseCallback) =
45-
handle.withPtr { ptr -> declareBackgroundMatchingListenerViaJNI(ptr, callback, onClose) }
40+
withPtr { ptr -> declareBackgroundMatchingListenerViaJNI(ptr, callback, onClose) }
4641

4742
@Throws(ZError::class)
48-
fun getMatchingStatus(): Boolean = handle.withPtr { ptr -> getMatchingStatusViaJNI(ptr) }
43+
fun getMatchingStatus(): Boolean = withPtr { ptr -> getMatchingStatusViaJNI(ptr) }
4944

50-
fun close() = handle.close(::freePtrViaJNI)
45+
fun close() = close { freePtrViaJNI(it) }
5146

5247
@Throws(ZError::class)
5348
private external fun putViaJNI(

zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIAdvancedSubscriber.kt

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,18 @@ package io.zenoh.jni
1616

1717
import io.zenoh.exceptions.ZError
1818
import io.zenoh.jni.callbacks.JNIOnCloseCallback
19-
import io.zenoh.jni.callbacks.JNISampleMissListenerCallback
2019
import io.zenoh.jni.callbacks.JNISampleCallback
20+
import io.zenoh.jni.callbacks.JNISampleMissListenerCallback
2121

22-
/**
23-
* Adapter class for a native Zenoh AdvancedSubscriber.
24-
*
25-
* @param initialPtr Raw pointer to the underlying native AdvancedSubscriber.
26-
*/
27-
public class JNIAdvancedSubscriber(initialPtr: Long) {
28-
private val handle = NativeHandle(initialPtr)
22+
/** Typed [NativeHandle] for a native Zenoh `AdvancedSubscriber`. */
23+
public class JNIAdvancedSubscriber(initialPtr: Long) : NativeHandle(initialPtr) {
2924

3025
@Throws(ZError::class)
3126
fun declareDetectPublishersSubscriber(
3227
history: Boolean,
3328
callback: JNISampleCallback,
3429
onClose: JNIOnCloseCallback,
35-
): JNISubscriber = handle.withPtr { ptr ->
30+
): JNISubscriber = withPtr { ptr ->
3631
JNISubscriber(declareDetectPublishersSubscriberViaJNI(ptr, history, callback, onClose))
3732
}
3833

@@ -41,27 +36,27 @@ public class JNIAdvancedSubscriber(initialPtr: Long) {
4136
history: Boolean,
4237
callback: JNISampleCallback,
4338
onClose: JNIOnCloseCallback,
44-
) = handle.withPtr { ptr ->
39+
) = withPtr { ptr ->
4540
declareBackgroundDetectPublishersSubscriberViaJNI(ptr, history, callback, onClose)
4641
}
4742

4843
@Throws(ZError::class)
4944
fun declareSampleMissListener(
5045
callback: JNISampleMissListenerCallback,
5146
onClose: JNIOnCloseCallback,
52-
): JNISampleMissListener = handle.withPtr { ptr ->
47+
): JNISampleMissListener = withPtr { ptr ->
5348
JNISampleMissListener(declareSampleMissListenerViaJNI(ptr, callback, onClose))
5449
}
5550

5651
@Throws(ZError::class)
5752
fun declareBackgroundSampleMissListener(
5853
callback: JNISampleMissListenerCallback,
5954
onClose: JNIOnCloseCallback,
60-
) = handle.withPtr { ptr ->
55+
) = withPtr { ptr ->
6156
declareBackgroundSampleMissListenerViaJNI(ptr, callback, onClose)
6257
}
6358

64-
fun close() = handle.close(::freePtrViaJNI)
59+
fun close() = close { freePtrViaJNI(it) }
6560

6661
@Throws(ZError::class)
6762
private external fun declareDetectPublishersSubscriberViaJNI(

zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIConfig.kt

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,14 @@ package io.zenoh.jni
1717
import io.zenoh.ZenohLoad
1818
import io.zenoh.exceptions.ZError
1919

20-
/** Adapter for the native Zenoh config. */
21-
public class JNIConfig(initialPtr: Long) {
22-
private val handle = NativeHandle(initialPtr)
23-
24-
/**
25-
* Pointer accessor for callers that need to pass the raw pointer
26-
* to another JNI method (e.g. `openSessionViaJNI(config.ptr)`).
27-
* Throws if the config has already been closed.
28-
*/
29-
internal val ptr: Long
30-
get() = handle.withPtr { it }
20+
/**
21+
* Typed [NativeHandle] for a native Zenoh `Config`. The `load*` and
22+
* `freePtrViaJNI` entry points aren't generated from zenoh-flat (the
23+
* Rust side is hand-written in `zenoh-jni/src/config.rs`), so the
24+
* companion's external funs stay here; instance methods that ARE
25+
* `#[prebindgen]` would delegate to [JNIWrappers].
26+
*/
27+
public class JNIConfig(initialPtr: Long) : NativeHandle(initialPtr) {
3128

3229
companion object {
3330

@@ -71,16 +68,16 @@ public class JNIConfig(initialPtr: Long) {
7168
private external fun getJsonViaJNI(ptr: Long, key: String): String
7269
}
7370

74-
fun close() = handle.close { freePtrViaJNI(it) }
71+
fun close() = close { freePtrViaJNI(it) }
7572

7673
@Throws(ZError::class)
77-
fun getId(): ByteArray = handle.withPtr { ptr -> getIdViaJNI(ptr) }
74+
fun getId(): ByteArray = withPtr { ptr -> getIdViaJNI(ptr) }
7875

7976
@Throws(ZError::class)
80-
fun getJson(key: String): String = handle.withPtr { ptr -> getJsonViaJNI(ptr, key) }
77+
fun getJson(key: String): String = withPtr { ptr -> getJsonViaJNI(ptr, key) }
8178

8279
@Throws(ZError::class)
83-
fun insertJson5(key: String, value: String) = handle.withPtr { ptr ->
80+
fun insertJson5(key: String, value: String) = withPtr { ptr ->
8481
insertJson5ViaJNI(ptr, key, value)
8582
}
8683
}

zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIKeyExpr.kt

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// This program and the accompanying materials are made available under the
55
// terms of the Eclipse Public License 2.0 which is available at
66
// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7-
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
7+
// which is available at https://www.apache.org/legal/epl-2.0.
88
//
99
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
1010
//
@@ -19,19 +19,13 @@ import io.zenoh.exceptions.ZError
1919
/**
2020
* Helpers for the key-expression JNI surface.
2121
*
22-
* The native side accepts `Any` for every key-expr parameter and
23-
* dispatches at runtime: a [Long] is treated as the
24-
* `Arc<KeyExpr<'static>>` registration handle, anything else
25-
* (a [String] in practice) is validated and converted to an owned
26-
* `KeyExpr<'static>`. Pass `handle ?: keyExprString` to native fns —
27-
* the `?:` operator picks the boxed [Long] when present, otherwise the
28-
* raw string.
29-
*
30-
* Functions that *return* a key-expression hand back a [Long] (the
31-
* Arc pointer); the canonical string is computed locally on the
32-
* Kotlin side. For [join] / [concat] the result string matches
33-
* Rust's `format!("{a}/{other}")` / `format!("{a}{other}")` since
34-
* the native validation is non-rewriting.
22+
* Operations that have a `#[prebindgen]` counterpart in `zenoh-flat`
23+
* (`try_from`, `autocanonize`, `intersects`, `includes`, `relation_to`,
24+
* `join`, `concat`) delegate to the generator-emitted wrappers in
25+
* [JNIWrappers]. The hand-written `dropKeyExprViaJNI` is retained as a
26+
* dedicated free entry point — it doesn't appear as a `#[prebindgen]`
27+
* fn because the consume semantic for a session-undeclare goes through
28+
* `undeclare_key_expr` instead.
3529
*/
3630

3731
/**
@@ -42,36 +36,36 @@ import io.zenoh.exceptions.ZError
4236
fun keyExprArg(handle: Long?, str: String): Any = handle ?: str
4337

4438
@Throws(ZError::class)
45-
fun keyExprTryFrom(keyExpr: String): String = JNINative.tryFromViaJNI(keyExpr)
39+
fun keyExprTryFrom(keyExpr: String): String = JNIWrappers.tryFrom(keyExpr)
4640

4741
@Throws(ZError::class)
48-
fun keyExprAutocanonize(keyExpr: String): String = JNINative.autocanonizeViaJNI(keyExpr)
42+
fun keyExprAutocanonize(keyExpr: String): String = JNIWrappers.autocanonize(keyExpr)
4943

5044
@Throws(ZError::class)
5145
fun keyExprIntersects(a: Long?, aStr: String, b: Long?, bStr: String): Boolean =
52-
JNINative.intersectsViaJNI(keyExprArg(a, aStr), keyExprArg(b, bStr))
46+
JNIWrappers.intersects(keyExprArg(a, aStr), keyExprArg(b, bStr))
5347

5448
@Throws(ZError::class)
5549
fun keyExprIncludes(a: Long?, aStr: String, b: Long?, bStr: String): Boolean =
56-
JNINative.includesViaJNI(keyExprArg(a, aStr), keyExprArg(b, bStr))
50+
JNIWrappers.includes(keyExprArg(a, aStr), keyExprArg(b, bStr))
5751

5852
@Throws(ZError::class)
5953
fun keyExprRelationTo(a: Long?, aStr: String, b: Long?, bStr: String): Int =
60-
JNINative.relationToViaJNI(keyExprArg(a, aStr), keyExprArg(b, bStr))
54+
JNIWrappers.relationTo(keyExprArg(a, aStr), keyExprArg(b, bStr))
6155

6256
/** Result of a join/concat: `(handle, canonicalString)`. */
6357
data class KeyExprResult(val handle: Long, val string: String)
6458

6559
@Throws(ZError::class)
6660
fun keyExprJoin(a: Long?, aStr: String, other: String): KeyExprResult {
67-
val handle = JNINative.joinViaJNI(keyExprArg(a, aStr), other)
61+
val handle = JNIWrappers.join(keyExprArg(a, aStr), other).peek()
6862
// Match Rust's `KeyExpr::join` formatting: "{self}/{other}".
6963
return KeyExprResult(handle, "$aStr/$other")
7064
}
7165

7266
@Throws(ZError::class)
7367
fun keyExprConcat(a: Long?, aStr: String, other: String): KeyExprResult {
74-
val handle = JNINative.concatViaJNI(keyExprArg(a, aStr), other)
68+
val handle = JNIWrappers.concat(keyExprArg(a, aStr), other).peek()
7569
// Match Rust's `KeyExpr::concat` formatting: "{self}{other}".
7670
return KeyExprResult(handle, "$aStr$other")
7771
}

zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNILivelinessToken.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,8 @@
1414

1515
package io.zenoh.jni
1616

17-
/** Adapter class for a native Zenoh LivelinessToken. */
18-
public class JNILivelinessToken(initialPtr: Long) {
19-
private val handle = NativeHandle(initialPtr)
20-
21-
fun undeclare() = handle.close(::undeclareViaJNI)
22-
17+
/** Typed [NativeHandle] for a native Zenoh `LivelinessToken`. */
18+
public class JNILivelinessToken(initialPtr: Long) : NativeHandle(initialPtr) {
19+
fun undeclare() = close { undeclareViaJNI(it) }
2320
private external fun undeclareViaJNI(ptr: Long)
2421
}

zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIMatchingListener.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,8 @@
1414

1515
package io.zenoh.jni
1616

17-
/** Adapter class for a native Zenoh MatchingListener. */
18-
public class JNIMatchingListener(initialPtr: Long) {
19-
private val handle = NativeHandle(initialPtr)
20-
21-
fun close() = handle.close(::freePtrViaJNI)
22-
17+
/** Typed [NativeHandle] for a native Zenoh `MatchingListener`. */
18+
public class JNIMatchingListener(initialPtr: Long) : NativeHandle(initialPtr) {
19+
fun close() = close { freePtrViaJNI(it) }
2320
private external fun freePtrViaJNI(ptr: Long)
2421
}

zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIPublisher.kt

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,25 @@
1515
package io.zenoh.jni
1616

1717
import io.zenoh.exceptions.ZError
18-
import io.zenoh.jni.JNINative.deletePublisherViaJNI
19-
import io.zenoh.jni.JNINative.putPublisherViaJNI
2018

2119
/**
22-
* Adapter class for a native Zenoh publisher. Uses primitive types for put/delete.
23-
*
24-
* @param initialPtr Raw pointer to the underlying native Publisher.
20+
* Typed [NativeHandle] for a native Zenoh `Publisher`. `put` and
21+
* `delete` delegate to the generator-emitted wrappers in
22+
* [JNIWrappers]; `freePtrViaJNI` is hand-written in Rust (the
23+
* by-value `drop_publisher` shape isn't a `#[prebindgen]` fn because
24+
* `Publisher` is not `Clone`), so [close] keeps the direct call.
2525
*/
26-
public class JNIPublisher(initialPtr: Long) {
27-
private val handle = NativeHandle(initialPtr)
26+
public class JNIPublisher(initialPtr: Long) : NativeHandle(initialPtr) {
2827

2928
@Throws(ZError::class)
30-
fun put(payload: ByteArray, encoding: JNIEncoding, attachment: ByteArray?) = handle.withPtr { ptr ->
31-
putPublisherViaJNI(ptr, payload, encoding, attachment)
32-
}
29+
fun put(payload: ByteArray, encoding: JNIEncoding, attachment: ByteArray?) =
30+
JNIWrappers.putPublisher(this, payload, encoding, attachment)
3331

3432
@Throws(ZError::class)
35-
fun delete(attachment: ByteArray?) = handle.withPtr { ptr ->
36-
deletePublisherViaJNI(ptr, attachment)
37-
}
33+
fun delete(attachment: ByteArray?) =
34+
JNIWrappers.deletePublisher(this, attachment)
3835

39-
fun close() = handle.close(::freePtrViaJNI)
36+
fun close() = close { freePtrViaJNI(it) }
4037

41-
// freePtrViaJNI is hand-written in zenoh-jni/src/publisher.rs because
42-
// the auto-generated `opaque_arc_input` convention clones the outer
43-
// Arc on borrow and drops the clone on exit, so the master Arc is
44-
// released via this dedicated entry point.
4538
private external fun freePtrViaJNI(ptr: Long)
4639
}

zenoh-jni-runtime/src/commonMain/kotlin/io/zenoh/jni/JNIQuerier.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ import io.zenoh.exceptions.ZError
1818
import io.zenoh.jni.callbacks.JNIGetCallback
1919
import io.zenoh.jni.callbacks.JNIOnCloseCallback
2020

21-
/** Adapter class for a native Zenoh querier. */
22-
public class JNIQuerier(initialPtr: Long) {
23-
private val handle = NativeHandle(initialPtr)
21+
/**
22+
* Typed [NativeHandle] for a native Zenoh `Querier`. `get` and
23+
* `freePtrViaJNI` are hand-written JNI entry points (not in
24+
* `zenoh-flat`), so they stay as `external fun` methods routed through
25+
* the inherited [withPtr].
26+
*/
27+
public class JNIQuerier(initialPtr: Long) : NativeHandle(initialPtr) {
2428

2529
@Throws(ZError::class)
2630
fun get(
@@ -32,7 +36,7 @@ public class JNIQuerier(initialPtr: Long) {
3236
attachmentBytes: ByteArray?,
3337
payload: ByteArray?,
3438
encoding: JNIEncoding?,
35-
) = handle.withPtr { ptr ->
39+
) = withPtr { ptr ->
3640
getViaJNI(ptr, keyExprArg(keyExprHandle, keyExprString), parameters, callback, onClose, attachmentBytes, payload, encoding)
3741
}
3842

@@ -50,5 +54,5 @@ public class JNIQuerier(initialPtr: Long) {
5054

5155
private external fun freePtrViaJNI(ptr: Long)
5256

53-
fun close() = handle.close(::freePtrViaJNI)
57+
fun close() = close { freePtrViaJNI(it) }
5458
}

0 commit comments

Comments
 (0)