Skip to main content

Module declared_qos

Module declared_qos 

Source
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 no nros::subscribe!. Every call site is an ordinary method call.
  • The topic is a runtime &str, not a const generic. A const assertion 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 was None and nothing could be compared.

§And two things are done with them, because the surfaces differ

  • check REFUSES a disagreement, with NodeError::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.
  • honour is what a RUST registration calls: it TAKES a declared depth shallower than the ask (the C++ three-argument NROS_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§

DeclaredEndpoint
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), or None when nobody declared that endpoint’s depth.
declared_durability
issue 1256 – the declared durability for (type_name, topic), or None.
declared_publisher
issue 1608 – the declared row for a PUBLISHER on (type_name, topic), or None. 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), or None.
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.