Skip to content

feat(052): runtime-neutral connector I/O - #248

Open
lxsaah wants to merge 16 commits into
mainfrom
feat/platform-independent-connectors
Open

feat(052): runtime-neutral connector I/O #248
lxsaah wants to merge 16 commits into
mainfrom
feat/platform-independent-connectors

Conversation

@lxsaah

@lxsaah lxsaah commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Implements wave A of design 052 — runtime-neutral connectors: the layer that lets an adapter own sockets, clocks and name resolution while a connector owns framing and protocol. A new runtime then costs one adapter crate and zero connector edits.

This PR is additive. Nothing consumes the new code on the live paths yet — the existing tokio_* / embassy_* connector modules are untouched and still own every production path. Migrating them (and deleting ~4 130 lines) is wave B.

What lands

Crate Change
aimdb-core session::ioByteStream, StreamDialer, StreamListener, Datagram, DatagramBinder, Delay, Framer; FramedConnection + FramingDialer/FramingListener; OneShot<T>
aimdb-tokio-adapter net feature — TokioNet::tcp/listen/udp, TokioDelay. Every future a plain async fn, no unsafe
aimdb-embassy-adapter net feature — EmbassyNet::tcp/listen::<N>/udp, EmbassyUart, EmbassyDelay. All force-Send for these paths lives here
aimdb-knx-connector neutral::connection_task — one task for both runtimes; TunnelIo::send gains + Send; embassy-sync/embassy-futures on std
aimdb-serial-connector neutral — the crate reduced to a COBS Framer; byte sources come from the adapters
aimdb-tcp-connector tests/neutral_pool.rs — the accept-pool proof
aimdb-mqtt-connector breaking: TlsOptions::new requires a Send RNG; TlsSlot becomes OneShot. Crate now carries zero unsafe impls (was two)

Design decisions worth review

The Send bound sits on each trait's return type, not at the use site. Generic connector code must produce Send futures at the boxing boundary, and return-type notation is still experimental on the pinned 1.98 toolchain. A std impl writes a plain async fn and the compiler discharges it; an Embassy impl returns the adapter's force-Send newtype. aimdb-core/src/session/io.rs carries a compile-time assertion, so dropping a bound fails in core rather than three crates away.

The Embassy listener stores one pending accept per slot rather than rebuilding them. TcpSocket::accept is a synchronous listen() plus a bare poll_fn, so dropping the future does not un-listen the socket — but re-entering accept() on a listening socket is an error, and the abort() that makes it re-enterable is what drops the LISTEN. tests/neutral_pool.rs holds both halves to real sockets, with a rebuild-and-cancel pool as a negative control that loses a SYN arriving between accepts.

Datagram::local_addr is part of the contract. Without it, unifying the KNX task would have silently downgraded every Tokio deployment to the NAT-style 0.0.0.0:0 HPAI that some gateways reject. unified_task_advertises_the_real_local_endpoint reads the CONNECT_REQUEST off the wire and asserts the real bound address.

embassy-sync and embassy-futures are executor-independent despite the names — neither pulls an executor, and embassy-futures has no dependencies at all. Both now back the KNX task on std. CriticalSectionRawMutex is the only Sync raw mutex embassy-sync offers, and it is a link-time obligation on std, so tokio-runtime enables critical-section/std itself and tests/shared_channel_on_std.rs proves the binary links.

Deviations from the design doc

  • EmbassyUart::new(rx, tx), not ::split — the caller has already split the UART; this joins the halves.
  • Acceptance criterion 3 relaxed: aimdb-serial-connector's tokio-runtime now depends on aimdb-tokio-adapter, so its byte source comes from the adapter on both runtimes instead of being duplicated. Recorded in that crate's CHANGELOG as an explicit reversal.
  • The TlsOptions gate is on the connector's embassy-tls path, not the demo — see below.

Incidental fixes

  • 23 rustdoc errors across six crates (public docs linking to private or feature-gated items), plus RUSTDOCFLAGS=-D warnings on make doc, which CI already runs — so this cannot regress silently.
  • make examples was broken and never run in CI. stm32-metapac 21 renamed the RCC enum variants, so all five embedded examples failed to compile. Fixed, and all five now build for thumbv8m.main-none-eabihf — their actual board architecture — instead of thumbv7em. thumbv8m.main is pinned in rust-toolchain.toml and the devcontainer.
  • Clippy never linted aimdb-core with connector-session; it does now.

Verification

Every commit was verified in isolation: unit + integration tests, clippy -D warnings on each feature configuration, thumbv7em cross-compilation, rustdoc, and cargo fmt --check. make examples passes end to end. Acceptance criterion 1 holds — core cross-compiles with the new traits and still contains zero unsafe.

The three remaining unsafe impls in connector crates are all in aimdb-tcp-connector/src/embassy_transport.rs, the module wave B deletes.

Not yet run: a full make check across the branch. Per-crate runs can miss feature-unification effects, and this branch changed feature graphs in four crates — CI is the check.

@lxsaah lxsaah changed the title feat(052): runtime-neutral connector I/O — wave A (additive) feat(052): runtime-neutral connector I/O Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant