KeyExpr class

A Zenoh key expression.

One type, two native backings:

  • a view backing (z_view_keyexpr_t), produced by the constructor, which borrows a native buffer this object allocates and releases; and
  • an owned backing (z_owned_keyexpr_t), produced by Session.declareKeyExpr.

Both loan to the same z_loaned_keyexpr_t, which is why every operation takes one and the same handle regardless of where the key expression came from — a declared key expression is not a separate type and needs no separate method.

The key expression domain, and where this binding is byte-exact

The grammar forbids //, a leading or trailing /, and the characters ?, # and $ (outside $*). It does not forbid an interior NUL, and canon accepts one: a key expression whose UTF-8 bytes are [97, 0, 98] is a real key expression. It is carried byte-exact through construction, declaration, concat, join and clone, and zenoh carries it across the wire byte-exact too.

The whole round trip is byte-exact. Every receive surface — a subscriber's Sample.keyExpr, a queryable's Query.keyExpr, a reply sample's key expression at either a getter or a Querier, and PullSubscriber.tryRecv — carries the key expression length-carried rather than as a C string, so an interior NUL survives delivery as well as sending.

⚠️ Non-ASCII key expressions are unusable with zenoh 1.8.0, and this is upstream, not a limit of this binding. A KeyExpr built from CJK, accented Latin or emoji text constructs and round-trips correctly here — but passing one to any session operation (put, declareSubscriber, Session.declareKeyExpr, …) panics inside zenoh's routing layer and aborts the process, at zenoh/src/net/routing/dispatcher/resource.rs (byte index N is not a char boundary). Keep key expressions ASCII until that is fixed upstream.

Canon form, and the two construction doors

A key expression is in canon form when its wildcards are spelled the one way zenoh treats as normal. hello/**/** and hello/** denote the same set of keys, but only the second is canon — every set of equivalent spellings has exactly one canon member.

There are two doors, and the strict one is the default:

  • KeyExpr.newstrict. It rejects a non-canon expression rather than quietly rewriting it, so the expression you passed is the one you get. Use it when a difference between what you wrote and what zenoh would use should be an error rather than a silent correction.
  • KeyExpr.autocanonize — the additive door. It rewrites the expression into canon form and constructs from the result. Use it when the input comes from somewhere you do not control.

Beside them, isCanon answers the question without constructing anything or throwing, and canonize performs the rewrite as a pure String transform — its documentation states the four rewrite rules with worked examples, since zenoh's own documentation states them nowhere.

⚠️ All four entry points judge the bytes, not the Dart String. A Dart string may hold a lone surrogate, and utf8.encode substitutes U+FFFD for it before zenoh sees a byte. So KeyExpr('a\uD800b').value reads back 'a�b', and canonize and autocanonize return the substituted form too. The round trip is byte-exact, which on that one input class is not the same thing as String-identical.

Must be disposed when no longer needed to release native memory. For a declared key expression, dispose is the local release: it frees this handle and unregisters nothing. Session.undeclareKeyExpr is the remote-visible act, and it consumes the handle.

This object holds a native handle, so it cannot cross an isolate boundary: a copy would share this one's native address while carrying its own fresh disposal flag, and the second release would be a use-after-free. Sending it throws ArgumentError naming the class.

It carries a NativeFinalizer safety net: if it is dropped without an explicit release, its native resources are reclaimed when the object is collected. ⛔ The net is not a substitute for releasing it explicitly — a finalizer runs at an unpredictable time, or not at all if the program exits first.

Implemented types

Constructors

KeyExpr(String expr)
Creates a KeyExpr from the given key expression string.
KeyExpr.autocanonize(String expr)
Creates a KeyExpr from expr, canonizing it first.
factory

Properties

hashCode int
The hash code for this object.
no setterinherited
nativePtr Pointer<Void>
Internal: returns the native pointer for use by Session.
no setter
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
value String
Returns the key expression as a Dart string.
no setter

Methods

clone() KeyExpr
Returns an independent copy of this key expression.
concat(String right) KeyExpr
Returns a new key expression with right appended, with no separator.
dispose() → void
Releases native resources held by this key expression.
equals(KeyExpr other) bool
Returns true if this key expression is equal to other in zenoh semantics.
includes(KeyExpr other) bool
Returns true if this key expression includes other.
intersects(KeyExpr other) bool
Returns true if this key expression intersects with other.
join(Object other) KeyExpr
Returns a new key expression joining this one to other with a /.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toString() String
A string representation of this object.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited

Static Methods

canonize(String keyExpr) String
Returns keyExpr rewritten into canon form.
isCanon(String keyExpr) bool
Reports whether keyExpr is a valid key expression in canon form.