Expand description
phase-454 W10 — the DECLARED QoS history depth, and the registration check
over it. Rust’s half of what C++ does with NROS_SUBSCRIBE’s
static_assert and C with NROS_ASSERT_DECLARED_DEPTH.
phase-454 W10 — the DECLARED QoS history depth, and what Rust does with it.
§What this is
The QoS history DEPTH of a subscription multiplies the executor arena:
sizeof(entry) + (depth + 1) * bound + (depth + 1) * 8. A build that sizes
from a declared depth and an image that registers a different one are an
image sized for one number and running another — so the two have to be held
to one. C++ holds them with a static_assert inside NROS_SUBSCRIBE, and C
with a _Static_assert inside NROS_ASSERT_DECLARED_DEPTH.
§Why Rust’s half is at REGISTRATION and not at compile time
Both C surfaces get a compile-time answer because a preprocessor macro sees the call site’s TOPIC as a token. Rust has neither of the two things that would make the same answer possible:
- No macro seam at the subscribe site.
nros::main!emits the boot scaffold and knows nothing about subscriptions; there is nonros::subscribe!. Every call site is an ordinary method call. - The topic is a runtime
&str, not a const generic. Aconstassertion would need it in the type system.
And the descriptor road differs too: a RUST component is registered as an
empty cmake INTERFACE library (NanoRosNodeRegister.cmake), compiled by the
workspace runtime crate rather than by that target, so there is no C
preprocessor in the lane and no include path to put a header on. That is why
_nros_declared_qos_arm() returns early for RUST — the header mechanism
is not available to it, not merely unimplemented.
§TWO facts arrive, on two roads
The declared depths reach nros-node/build.rs from whichever carrier the
road has, and it writes both into crate::config::DECLARED_QOS_ROWS:
- the cmake road (native C/C++, Zephyr west, NuttX) sets
NROS_ENTITY_DECLARED_DEPTHS(type|topic=depth), written by the entity inventory from the resolved SystemModel; - the single-package cargo leaf road — the one phase-454 W12 taught to
read a
system.contract.yaml— sets no such variable and names a SIZING DESCRIPTOR instead, whose[[endpoint]]rows carry the same fact (RFC-0100 D4). W10 shipped reading only the first, so on exactly the road that had a contract this table wasNoneand nothing could be compared.
§And two things are done with them, because the surfaces differ
checkREFUSES a disagreement, withNodeError::DeclaredDepthMismatch— the registration fails, the subscription never exists, and the entry’s?carries it out. Reached from the C and C++ FFI seams, which took the declared depth at their own call site already.honouris what a RUST registration calls: it TAKES a declared depth shallower than the ask (the C++ three-argumentNROS_SUBSCRIBE’s answer, delivered one layer down because Rust has no call-site seam) and refuses a declaration DEEPER than the ask. Its doc comment has the whole rule and why the asymmetry is real.
§ABSENCE IS NOT ZERO
A (type, topic) with no row is “nobody declared this endpoint”. Nothing is
checked for it, nothing is taken, and nothing is defaulted. An image with no
contract sidecar has DECLARED_QOS_ROWS == None and behaves exactly as it
did before — measured, not asserted: on examples/linux/rust/listener with
the sidecar removed, .bss + .data and every attributed symbol are
identical to origin/main’s, and the image carries no declared_qos symbol
at all.
§issue 1256 – RELIABILITY and DURABILITY too
A contract can state three things about a subscription and this module now
reads all three. The two policies are not a sizing fact the way depth is;
they are an INTEROP one – an incompatible-QoS match never delivers – and
until this they were declared, delivered to the build and never compared
with the code. They arrive on the sizing DESCRIPTOR only (no env knob is
added for them: re-carrying a fact the descriptor already states is the
0460/0491 shape), and check / honour treat them by the same rules as
the depth, with the order of the two values standing in for “deeper”.
§issue 1608 – PUBLISHERS too, with the policy direction REVERSED
A contract can state the same three things about a publisher, and
transient_local is the one QoS fact that is publisher-side by nature: it is
what a zenoh image spends a queryable slot on. The descriptor’s publisher
rows reach DECLARED_PUBLISHER_QOS_ROWS
(a table of its own: a publisher and a subscription on one (type, topic)
are two endpoints), and every publisher registration – the Rust seams and
the C/C++ FFI seams alike – goes through
honour_publisher.
Its rule is NOT the subscription’s copied across. Reliability and durability
are matched request-vs-offered, so the tolerant direction flips: a reader may
ask for less than a writer offers, a writer may offer more than a reader asks.
A publisher asking LESS than its declaration is therefore RAISED to it (the
build reserved it, and every reader that matched the lower offer still
matches); one asking MORE is REFUSED (lowering it could break a match, and
keeping it rides storage the build did not count). The depth rule is shared.
Measured on examples/linux/rust/talker with a contract declaring
/chatter transient_local, depth 1: the default publisher registers
transient_local, depth 1, and reports both takes; declaring best_effort
instead refuses the registration and the image exits naming the topic.
Re-exports§
pub use crate::config::DECLARED_QOS_ROWS;pub use crate::config::DECLARED_PUBLISHER_QOS_ROWS;
Structs§
- Declared
Endpoint - One subscription this image’s contract declares something about.
Functions§
- check
- Refuse a subscription whose QoS disagrees with what the contract declared for its topic – its depth, and (issue 1256) its reliability and durability.
- declared_
depth - The declared depth for
(type_name, topic), orNonewhen nobody declared that endpoint’s depth. - declared_
durability - issue 1256 – the declared durability for
(type_name, topic), orNone. - declared_
publisher - issue 1608 – the declared row for a PUBLISHER on
(type_name, topic), orNone. A table of its own because a publisher and a subscription on one(type, topic)are two endpoints with two declarations. - declared_
reliability - issue 1256 – the declared reliability for
(type_name, topic), orNone. - honour
- The QoS a Rust subscription actually registers with, once the contract has had its say — phase-454 W13, the Rust half of W10, widened to the two policies by issue 1256.
- honour_
publisher - issue 1608 – the PUBLISHER counterpart of
honour: the QoS a publisher registers with once the contract has had its say.