Skip to content

feat: reg.input / reg.output, connector handles and publish / subscribe (#388) - #392

Merged
lxsaah merged 13 commits into
mainfrom
feature/388-input-output-connections
Nov 2, 2026
Merged

lxsaah merged 13 commits into
mainfrom
feature/388-input-output-connections

Conversation

@lxsaah

@lxsaah lxsaah commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Description

Implements #388: wiring a record to its inputs and outputs so that a wrong wiring is a compile error where possible, and a build() error otherwise. Each sub-issue was merged into this branch through its own PRs.

let mut builder = AimDbBuilder::new().runtime(runtime);
let mqtt = builder.connect(MqttConnector::new(broker_url));
let SimThermometers { indoor, .. } = SimThermometers::new();

builder.configure::<Temperature>(SensorKey::TempIndoor, |reg| {
    reg.buffer(BufferCfg::SpmcRing { capacity: 10 })
        .input(Thermometer::on(indoor))            // an Input for every T: From<Reading>
        .tap(temperature_logger)
        .output(publish(mqtt, "sensors/temp/indoor").with_qos(1));  // the contract's own codec
});

#389: detachable links, Input / Output (#393–#396)

  • One link builder per direction, generic over what it's attached to: OutboundLinkBuilder<T, R> / InboundLinkBuilder<T, R>.
    • OutboundConnectorBuilder / InboundConnectorBuilder remain as aliases, so link_to(..)…finish() and existing extension impls compile unchanged.
    • The detached form OutboundLink<T> / InboundLink<T> is built with new(url).
  • Link validation moved into the registrar, so attached and detached links go through the same checks.
  • Input<T> / Output<T> with #[diagnostic::on_unimplemented], plus reg.input(..) / reg.output(..).
  • The MQTT, Zenoh and LinkCodecBuilderExt extension traits apply to both forms.

#390: connect and ConnectorHandle (#397–#399)

  • AimDbBuilder::connect(c) -> ConnectorHandle: a Copy handle holding the builder's id and the connector's index. It stores no scheme string.
  • OutboundLink::on(handle, address) / InboundLink::on(..):
    • A bare address takes the connector's scheme.
    • A full URL (#[link_address] keys) must match it.
    • A wrong scheme, or another builder's handle, is reported by build().

#391: publish / subscribe, demos, conventions (#400–#404)

  • publish(handle, address) / subscribe(..) for Linkable contracts: plain links in the contract's codec that report its schema, through the new with_schema link option. Every connector option applies.

  • linked_to / linked_from / *_with share their implementation, with unchanged behaviour.

  • mqtt-connector-demo-common is the shared, runtime-agnostic crate:

    • contracts that are always Linkable, with the hand-rolled no_std JSON removed
    • keys
    • SimThermometers / Thermometer: owned channels, one input for every T: From<Reading>
    • monitors
  • Both MQTT demos use connect + publish / subscribe. The embassy demo gains board.rs, and B1 becomes a PushButton input publishing ButtonPress.

  • The usage guide documents the conventions:

    • inputs yield events, and records are built From<Event>
    • device channels are owned
    • where the From impls live
    • a table of what is checked at compile time and what at build()

    Input's rustdoc has a compile_fail,E0382 doctest. The guide's Tokio examples were fixed to compile, and its crate versions updated.

Compatibility

No source changes are required. Two behaviour changes:

  • #[must_use] on the link builders. A link_to(..) / link_from(..) whose .finish() is missing now warns, which is an error under -D warnings. Before, such a link was silently dropped. No code in this repository had one.
  • The "conflicting writers" build() error names kinds (source + inbound link) instead of methods (.source()).

Embassy MQTT demo firmware, release thumbv8m.main-none-eabihf:

section before after
.text 557,548 567,068
.rodata 65,568 67,352

The shared input brings .text to 539,948 without the button; the new B1 record adds the rest.

Tested against a broker

Both MQTT demos were run against the dev/mosquitto bench broker (authenticated, plain 1883) on the developer host:

  • tokio-mqtt-connector-demo: all 15 readings published on sensors/temp/{indoor,outdoor,server_room}, with the expected JSON. Commands on commands/temp/indoor / outdoor were received by the demo.

  • embassy-mqtt-connector-demo, flashed on a Nucleo-H563ZI with probe-rs:

    • DHCP, then the MQTT connect with credentials and both subscriptions.
    • Thermometer readings published continuously, with JSON identical to the Tokio demo's.
    • Both commands received on the board.
    • B1: 7 presses published to sensors/button/b1 ({"button":"b1","press":1..7}), each exactly once and in order.

    The tls build was compiled and linted, but not run against the TLS listener.

Related Issue

Checklist

  • I have read the CONTRIBUTING.md document.
  • My code follows the project's coding standards.
  • I have added tests to cover my changes.
  • All new and existing tests passed (make check): CI on this PR.
  • I have updated the documentation accordingly.

🤖 Generated with Claude Code

@lxsaah lxsaah changed the title feat: reg.input / reg.output with connection handles (#388) feat: reg.input / reg.output, connector handles and publish / subscribe (#388) Nov 2, 2026
@lxsaah
lxsaah marked this pull request as ready for review November 2, 2026 20:12
@lxsaah
lxsaah merged commit 5b8b9fe into main Nov 2, 2026
12 checks passed
@lxsaah
lxsaah deleted the feature/388-input-output-connections branch November 2, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants