Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
370d3ac
Extract SdStateManager from server mod
JustinKovacich Apr 22, 2026
9c73ab8
Shifted tests around, added a test, removed dead impl Default
JustinKovacich Apr 22, 2026
4f9f709
Add multicast-loopback coverage for SdStateManager::send_offer_service
JustinKovacich Apr 23, 2026
d3315e8
fmt: apply rustfmt style to the new multicast tests
JustinKovacich Apr 23, 2026
e9d1805
server: track SD session wrap, propagate reboot flag everywhere
JustinKovacich Apr 23, 2026
3116a1c
server: fix SD wrap-flag ordering across all emission paths
JustinKovacich Apr 23, 2026
7f975cc
round-3: drop branch-specific note from #[ignore] reason
JustinKovacich Apr 24, 2026
ada2553
Switch to existing collections to heapless, hide other non-embedded f…
JustinKovacich Apr 22, 2026
a36af2f
Address PR #76 review feedback
JustinKovacich Apr 23, 2026
7d3da6e
phase 2: cover pending_responses saturation branch
JustinKovacich Apr 23, 2026
540899d
client+server: harden re-enqueue + misc Copilot round-2
JustinKovacich Apr 23, 2026
d6cca3a
chore(clippy): add Panics doc + safe cast in move_vec PR
JustinKovacich Apr 23, 2026
951b02d
round-3: handle displaced-sender branch in pending_responses insert
JustinKovacich Apr 24, 2026
073ee80
docs(error): flag variant additions on client::Error as breaking
JustinKovacich Apr 24, 2026
34e1a05
server: NACK on Subscribe capacity overflow instead of false ACK
JustinKovacich Apr 24, 2026
97eca58
round-4: address Copilot feedback on session/sub_manager docs + log w…
JustinKovacich Apr 24, 2026
cea2204
round-5: clean up Subscribe-NACK reason path + CHANGELOG + doc
JustinKovacich Apr 24, 2026
5a804cf
PR #76 round: trim stale changelog, specific NACK reasons, truthful s…
JustinKovacich Apr 24, 2026
bceae77
Update src/server/mod.rs
JustinKovacich Apr 24, 2026
3881278
Max buffer size set to 1500, avoid heap allocation/vecs, overflow ret…
JustinKovacich Apr 22, 2026
3b4c10f
Responding to PR Feedback
JustinKovacich Apr 23, 2026
92cf7f8
phase 3: add coverage for publish_event pre-encode overflow branch
JustinKovacich Apr 23, 2026
cb2c7ed
docs: clarify UDP_BUFFER_SIZE scope + wording (Copilot round-2)
JustinKovacich Apr 23, 2026
edea683
round-3: clarify UDP_BUFFER_SIZE + memory-footprint docs
JustinKovacich Apr 24, 2026
4aadf73
test(event_publisher): cover E2E-protected overflow guard in publish_…
JustinKovacich Apr 24, 2026
9fbd8e0
round-4: fix E2E-overflow log wording + MTU-vs-UDP_BUFFER_SIZE comment
JustinKovacich Apr 24, 2026
32233bd
fix(event_publisher): guard against usize overflow in raw-event total…
JustinKovacich Apr 24, 2026
f5bf200
round-5: derive oversize fixtures from UDP_BUFFER_SIZE + fix log wording
JustinKovacich Apr 24, 2026
b786551
Added Transport Socket, Transport Factory and Timer traits
JustinKovacich Apr 22, 2026
495f661
phase 4: rewrite Send-bound docs to remove nonexistent type reference
JustinKovacich Apr 23, 2026
2b5dd3e
docs: fix transport.rs + lib.rs module-level accuracy (Copilot round-2)
JustinKovacich Apr 23, 2026
3e0b68c
docs: reword transport-module doc on lib.rs to match transport.rs
JustinKovacich Apr 23, 2026
1a35836
docs: drop pub on structs inside doctest wrapper fn
JustinKovacich Apr 24, 2026
db44209
transport: make TransportSocket I/O methods take &self
JustinKovacich Apr 24, 2026
756f4b2
docs(transport): correct backend wording; add Errors sections
JustinKovacich Apr 24, 2026
40b82f4
Add a new tokio transport layer that uses semantics identical to the …
JustinKovacich Apr 22, 2026
6b85988
bind_discovery_seeded and bind are async and construct a TokioSocket …
JustinKovacich Apr 22, 2026
8526f9f
Added bind_with_transport methods that accept a factory that produces…
JustinKovacich Apr 22, 2026
e37d061
Responding to PR feedback
JustinKovacich Apr 22, 2026
5fd8387
phase 5: respond to PR #79 feedback
JustinKovacich Apr 23, 2026
d50d21b
tokio_transport: document truncation caveat + triage log levels
JustinKovacich Apr 23, 2026
f76c2b6
docs: fix transport.rs intra-doc links under default features
JustinKovacich Apr 23, 2026
e703de2
chore(clippy): tidy new warnings in tokio_transport
JustinKovacich Apr 23, 2026
2b46f0b
fix(socket_manager): correct error log on recv_from failure
JustinKovacich Apr 24, 2026
24a470c
round-N: align map_io_error + spawn_socket_loop docs with implementation
JustinKovacich Apr 24, 2026
d9e08c4
client/socket_manager: clean up error-log + if-let-Ok patterns
JustinKovacich Apr 24, 2026
24aef9d
Potential fix for pull request finding
JustinKovacich Apr 24, 2026
92cf168
fix(rebase): resolve semantic conflicts from base-trait migration
JustinKovacich Apr 25, 2026
94cb236
Apply hoists: run_future doesnt call tokio::spawn, client::new/with_l…
JustinKovacich Apr 22, 2026
07f7abe
Add testing, add sensible panics, updated docs
JustinKovacich Apr 23, 2026
84ee4e8
phase 6: respond to PR #80 feedback (typed Shutdown + test/doc fixes)
JustinKovacich Apr 23, 2026
7a8d2d4
lints: address must_use + README wording (Copilot round-2)
JustinKovacich Apr 23, 2026
a1a01ed
chore(clippy): address new warnings in hoist_tokio PR
JustinKovacich Apr 23, 2026
ffffa1a
PR #80 round: apply reviewer suggestions
JustinKovacich Apr 24, 2026
452e47b
examples: bind spawn handle in client_server to avoid let_underscore_…
JustinKovacich Apr 24, 2026
6646cf3
server: add #[must_use] to announcement_loop
JustinKovacich Apr 24, 2026
118c8ce
client: distinguish pending_responses saturation from shutdown
JustinKovacich Apr 24, 2026
8964f75
docs(error): add "pending_responses" to Capacity tag list
JustinKovacich Apr 24, 2026
92606c1
fix: capture tokio::spawn JoinHandle to avoid unused_must_use warnings
JustinKovacich Apr 24, 2026
d92c5a3
fix: store and observe JoinHandles in production/example code
JustinKovacich Apr 24, 2026
861c5d3
fix: use Tokio-specific wording and unique test service IDs
JustinKovacich Apr 25, 2026
82df573
docs(server): fix Result signatures and executor wording in README AP…
JustinKovacich Apr 25, 2026
398289b
phase 7: select-fairness, FusedFuture migration, Timer trait wiring
JustinKovacich Apr 25, 2026
e4ab414
phase 8: bare_metal example as trait-surface canary
JustinKovacich Apr 25, 2026
e87c128
phase 9: Spawner trait + executor-agnostic Client construction
JustinKovacich Apr 25, 2026
81d1dee
phase 9: round-N response to consolidated review feedback
JustinKovacich Apr 27, 2026
43118c7
phase 10: lock-handle abstraction (Arc<Mutex/RwLock<_>> → trait handles)
JustinKovacich Apr 27, 2026
fbc2998
phase 11: channel replacement (tokio::sync → ChannelFactory trait)
JustinKovacich Apr 27, 2026
d31fa2d
phase 12: socket-bound relax via TransportSocket GATs
JustinKovacich Apr 27, 2026
05565d7
phase 13a: feature-flag detangle (client side)
JustinKovacich Apr 27, 2026
97553d6
phase 13.5: no-tokio Client construction
JustinKovacich Apr 27, 2026
0cc8b25
phase 13.6a: ChannelFactory bounded const-N quirk fix
JustinKovacich Apr 28, 2026
fd01d5c
phase 13.6b: ChannelFactory per-T Pooled<C> bounds
JustinKovacich Apr 28, 2026
6cbece8
phase 13.6c: src/static_channels/ pool primitives
JustinKovacich Apr 28, 2026
c17e0f6
phase 13.6d: define_static_channels! macro
JustinKovacich Apr 28, 2026
1bd1fc0
phase 13.6e: alloc-counting witness + bare_metal_client uses StaticCh…
JustinKovacich Apr 28, 2026
6547a91
phase 13.6f: waker tests, Debug impls, macro vis fragment, drop spuri…
JustinKovacich Apr 28, 2026
7c57598
phase 14a: server feature-flag detangle (topology only)
JustinKovacich Apr 28, 2026
e2e9a73
phase 14a fixup: refresh stale doc text after the server split
JustinKovacich Apr 28, 2026
22a1737
phase 14b: server engine retargeting (Server reachable without tokio)
JustinKovacich Apr 28, 2026
b4f4c96
phase 15: rewrite bare_metal example as Client::new_with_deps integra…
JustinKovacich Apr 28, 2026
7171ffc
phase 15: add bare_metal_server example; rename bare_metal → bare_met…
JustinKovacich Apr 28, 2026
503a55d
phase 16: no-alloc CI gate — StaticE2EHandle, AtomicInterfaceHandle, …
JustinKovacich Apr 28, 2026
085c3f7
phase 16 review: explicit CI gate, first-claim/recv/Profile5 witnesses,
JustinKovacich Apr 28, 2026
732cd89
cleanup: fix three correctness bugs in transport / E2E / server bind
JustinKovacich Apr 28, 2026
2d9238f
cleanup: honor close-semantic contracts on embassy + static-pool back…
JustinKovacich Apr 28, 2026
6a22fd2
cleanup: !Send Client construction via LocalSpawner + BindDispatch
JustinKovacich Apr 28, 2026
7c58649
cleanup: drop per-event allocations + Send bounds from server hot path
JustinKovacich Apr 28, 2026
76e4b21
cleanup: fix MockRecvFut busy-wake + MockTimer duration violations
JustinKovacich Apr 28, 2026
3f6e027
fix: phase 17 cleanup - docs, API alignment, alloc gating
JustinKovacich Apr 28, 2026
4c099ac
Fix tests so they run serially and don't flake.
JustinKovacich Apr 28, 2026
2d1c768
Fix waker being held during waker.wake when it didnt need to be
JustinKovacich Apr 28, 2026
850800c
Improve code coverage and remove dead code.
JustinKovacich Apr 28, 2026
1f2fd79
fix: address round-2 review comments on #95/#96
JustinKovacich Apr 28, 2026
8303b31
fix: address adversarial review for #95 (3 Crit + 12 High + 13 Med + …
JustinKovacich Apr 28, 2026
fe618cf
fix(examples): port workspace example mocks to GAT BindFuture/SleepFu…
JustinKovacich Apr 28, 2026
61c67f4
test: add regression tests for H3/H4/H5/H10/H12
JustinKovacich Apr 28, 2026
de31890
chore: remove accidentally-committed local config files
JustinKovacich Apr 28, 2026
dcb0f83
fix: address remaining Copilot inline comments on #95
JustinKovacich Apr 28, 2026
9aa2619
docs: correct assert_no_alloc semantics (abort, not panic)
JustinKovacich Apr 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .config/nextest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,23 @@ leak-timeout = "1s"
filter = 'test(server::tests::) | binary(client_server)'
test-group = 'serial-sd-port'

# bare_metal_e2e tests share static channel pools declared via
# `define_static_channels!` — pool slots are not reclaimed until the
# process exits, so parallel tests exhaust the pools. Run serially.
[[profile.default.overrides]]
filter = 'binary(bare_metal_e2e)'
test-group = 'serial-static-pools'

# static_channels_alloc_witness tests share a counting global allocator
# and static channel pools. The internal MEASURE_LOCK serializes allocation
# measurement, but pool exhaustion still requires serial execution.
[[profile.default.overrides]]
filter = 'binary(static_channels_alloc_witness)'
test-group = 'serial-static-pools'

[test-groups]
serial-sd-port = { max-threads = 1 }
serial-static-pools = { max-threads = 1 }

[profile.default.junit] # Output the junit coverage for tools
path = "junit.xml"
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@ jobs:
with:
tool: cargo-llvm-cov, cargo-nextest
- run: cargo test --no-default-features
- name: Build matrix — partial feature subsets
run: |
cargo build --no-default-features --features bare_metal
cargo build --no-default-features --features embassy_channels
cargo build --no-default-features --features client
cargo build --no-default-features --features server
cargo build --no-default-features --features client,server
- name: Doc — partial feature subsets (catch unresolved intra-doc links)
env:
RUSTDOCFLAGS: -D warnings
run: |
cargo doc --no-deps --no-default-features --features client
cargo doc --no-deps --no-default-features --features server,bare_metal
cargo doc --no-deps --all-features
- name: No-alloc witness (explicit gate)
run: cargo test --features client,bare_metal --test no_alloc_witness
- run: cargo llvm-cov nextest --all-features --lcov --output-path ./target/lcov.info
- name: Upload Coverage report
uses: codecov/codecov-action@v5
Expand Down
7 changes: 3 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
.DS_Store

/target

.claude/
CLAUDE.md

.DS_Store
lcov.info
/target
51 changes: 48 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,56 @@
# Changelog

## [Unreleased]
## [0.8.0]

### Added

- **`client::Error::Capacity(&'static str)`** — new variant returned when a fixed-capacity internal structure is full. Current tags: `"unicast_sockets"`, `"udp_buffer"`, `"pending_responses"`, `"request_queue"`. Because `client::Error` is not `#[non_exhaustive]`, this is a breaking change for downstream crates that match the enum exhaustively.
- **`client::Error::Transport(crate::transport::TransportError)`** — new variant surfacing failures from the pluggable transport backend (`#[from]`-converted, displays transparently). Same exhaustive-match caveat as above.
- **`client::Error::Shutdown`** — new variant returned by every `Client` method when the control channel is closed (run-loop future was dropped, cancelled, or exited). Replaces the previous `.unwrap()`-on-closed-channel panic path.
- **`server::SubscribeError`** — new public enum (`SubscribersPerGroupFull`, `EventGroupsFull`) returned by `SubscriptionManager::subscribe` and `EventPublisher::register_subscriber` when a bounded capacity rejects a subscription. Re-exported from `server::mod`.
- **`Client::new_with_loopback(interface, multicast_loopback)`** — constructor that exposes the previously-internal `multicast_loopback` knob for same-host integration tests.
- **`Client::new_with_spawner_and_loopback(interface, multicast_loopback, spawner)`** — executor-agnostic constructor that accepts a caller-supplied `Spawner` impl. Bare-metal callers swap `TokioSpawner` for their own task pool.
- **`Client::new_with_deps_local`** — constructor for single-threaded / `!Send` executors. Accepts a `LocalSpawner` instead of `Spawner` and relaxes the `Send` bound on the transport socket.
- **`transport::Spawner` trait** (re-exported as `simple_someip::Spawner`) — executor-agnostic task-spawn abstraction. `tokio_transport::TokioSpawner` is the default `std + tokio` impl.
- **`transport::LocalSpawner` trait** — single-threaded task-spawn abstraction for `!Send` futures. Enables use on runtimes like `tokio::LocalSet` or embassy's single-threaded executor.
- **`transport::TransportSocket` / `TransportFactory` / `Timer` traits** — executor-agnostic UDP transport abstraction. Default `tokio_transport::TokioTransport` / `TokioSocket` / `TokioTimer` impls available behind the `client-tokio` / `server-tokio` features.
- **`bare_metal` cargo feature** — activates embassy-sync as the channel backend and enables the `static_channels` module, `AtomicInterfaceHandle`, and `StaticE2EHandle` types. The heap-backed `EmbassySyncChannels` factory is separately gated by the `embassy_channels` feature (which implies `bare_metal`). See `examples/bare_metal_client/` and `examples/bare_metal_server/` for runnable integration examples. Validate with `cargo build -p bare_metal_client` / `cargo build -p bare_metal_server`, NOT `cargo build --workspace` (workspace builds may unify features and mask regressions).
- **`SubscriptionManager::subscribe` returning a `Result`** — see "Changed" below; the regression test list now exercises the major-version mismatch path explicitly.

### Changed

- **`std` is now the default feature** — the crate enables `std` (with `thiserror` and `tracing`) by default. Users targeting `no_std` environments must set `default-features = false` in their `Cargo.toml`.
- **`thiserror` and `tracing` use `default-features = false`** — both dependencies are always included but their `std` features are only enabled when the crate's `std` feature is active. This removes the need for `#[cfg(feature = "std")]` gating on error types and logging macros.
- **Breaking: `Client::new(interface)` return shape** — previously returned `(Client, ClientUpdates)`; now returns `(Client, ClientUpdates, impl Future<Output = ()> + Send + 'static)`. The third element is the run-loop future, which the caller MUST drive (typically via `tokio::spawn`) for any `Client` method to make progress. Migration: change destructuring to a 3-tuple and spawn or otherwise actively poll the future.
- **Breaking: `Server::start_announcing` removed → `Server::announcement_loop`** — the new method returns `Result<impl Future<Output = ()> + Send + 'static, Error>` (annotated `#[must_use]`). Spawn the returned future to fire announcements; calling and dropping the future is a silent no-op.
- **Breaking: `Client::start_sd_announcements` renamed to `Client::sd_announcements_loop`** — same semantic shift as `announcement_loop`: returns an `impl Future` instead of spawning internally, so the caller drives execution.
- **Breaking: `Client::reboot_flag(&self)` now returns `Result<protocol::sd::RebootFlag, Error>`** — previously returned the bare flag and could panic if the run-loop had exited. All other public `Client` methods migrated to the same `Err(Error::Shutdown)` policy in this release; `reboot_flag` is now consistent.
- **Breaking: `server::SubscriptionManager::subscribe` signature change** — now returns `Result<(), server::SubscribeError>` instead of `()`. Previously, capacity rejections were silently dropped with only a `warn!` log, which let the server emit a `SubscribeAck` for a subscription that had not been recorded. Callers must now handle the `Err` path (the server's own SD loop emits `SubscribeNack` on `Err`).
- **Breaking: `server::EventPublisher::register_subscriber` signature change** — now returns `Result<(), server::SubscribeError>` instead of `()`, surfacing the same capacity-rejection signal to externally managed subscription dispatchers.
- **Breaking: `Server::unicast_local_addr` return type changed** — previously returned `Result<std::net::SocketAddr, std::io::Error>`; now returns `Result<std::net::SocketAddr, server::Error>`. Callers that pattern-matched on `std::io::Error` must update to `server::Error::Transport(e)` and access the inner `TransportError` from there.
- **Breaking: default features changed `default = []` → `default = ["std"]`** — previously `embedded-io/std`, `thiserror/std`, and `tracing/std` were always-on; they are now gated behind the new `std` feature. Downstream consumers building with `default-features = false` who relied on the implicit `std` propagation must add `features = ["std"]` (or one of `client` / `server`, which both imply `std`).
- **Breaking: `Client::new` type signature now `Client::<M, R, I, C>::new`** — the `Client` struct gained three additional type parameters for the executor traits (`R: TransportFactory`, `I: InterfaceHandle`, `C: ChannelFactory`). The tokio-default convenience constructor is now gated behind the `client-tokio` feature (was `client`). Migration: add `features = ["client-tokio"]` to continue using `Client::new`; trait-surface consumers use `Client::new_with_deps`.
- **Breaking: `Server::new` type signature now `Server::<R, S, F, Tm>::new`** — the `Server` struct gained type parameters for the pluggable backends. The tokio-default convenience constructor is now gated behind the `server-tokio` feature (was `server`). Migration: add `features = ["server-tokio"]` to continue using `Server::new`; trait-surface consumers use `Server::new_with_deps`.
- **Breaking: `SubscriptionHandle` trait redesigned** — the previous `get_subscribers(&self, …) -> impl Future<Output = Vec<Subscriber>>` method has been replaced with `for_each_subscriber(&self, …, f: FnMut)` visitor pattern. This allows `EventPublisher::publish_event` to copy subscriber addresses into a stack buffer (`heapless::Vec<_, 16>`) instead of allocating per-event. Implementors of custom `SubscriptionHandle` must migrate.
- **Breaking: `SubscriptionHandle` RPITIT futures no longer `+ Send`** — the `subscribe`, `unsubscribe`, and `for_each_subscriber` methods now return `impl Future<…>` without a `+ Send` bound. This enables single-threaded lock-free implementations on bare-metal targets, but means `SubscriptionHandle` trait objects cannot be held across `.await` points in multi-threaded executors. Direct usage with the default `Arc<RwLock<SubscriptionManager>>` is unaffected.
- New optional dependency `dep:futures` (default-features-off) for `futures::select!` + `FusedFuture` plumbing — pulled in transitively by both `client` and `server` features.
- `client::Error::Transport` adopts `#[error(transparent)]` Display delegation (the previous wrapping with `{:?}` debug-formatted the inner `TransportError`); user-facing error strings are now stable.
- Subscribe-NACK reason strings normalized to `snake_case` for log consistency: `wrong_service_id`, `wrong_instance_id`, `wrong_major_version`, `no_endpoint_in_options`, `subscribers_per_group_full`, `event_groups_full`. Wire format is unchanged (NACK is signalled by `TTL=0`).

### Fixed

- **`server::EventPublisher::publish_event` no longer silently sends UNPROTECTED payloads on E2E protect failure** — counter exhaustion / key-lookup races etc. now surface as `Err(Error::E2e(_))` rather than logging and falling through (which had been emitting an unprotected message claiming an E2E-protected channel).
- **SD `Subscribe` with mismatched `major_version` is now NACKed** — previously an Ack would be returned and the subscription registered, leaving the application stack to silently mis-decode incompatible-version traffic.
- **`SocketManager::send` no longer panics on a dropped response oneshot** — user-supplied `Spawner` made this path reachable; failures now return `Err(Error::SocketClosedUnexpectedly)`.
- **`client::Inner` request-queue overflow no longer drops control messages silently** — full queue now invokes `reject_with_capacity("request_queue")` on the rejected message, so callers see a typed `Err(Error::Capacity("request_queue"))` instead of a `RecvError` mapped to `Error::Shutdown`.
- **Per-socket recv-error hot loop bounded** — `SocketManager`'s socket loop now closes after `MAX_CONSECUTIVE_RECV_ERRORS = 16` consecutive `recv_from` failures rather than spinning indefinitely on a permanently broken fd.
- **`Client::send` fails fast on oversize messages** — pre-encode size check returns `Err(Error::Capacity("udp_buffer"))` for messages whose `required_size()` exceeds `UDP_BUFFER_SIZE`. Mirrors the existing `EventPublisher::publish_event` capacity guard.

### Notes

- **Crate version bumped to 0.8.0** — reflects the breaking changes above. Downstream `Cargo.toml` snippets in `README.md` were updated accordingly.

### Test runner

- `tests/client_server.rs` integration tests share the SD multicast port (30490) via `SO_REUSEPORT` and rely on Linux's reuseport hashing for traffic delivery. Under cargo's default parallel test runner cross-test Subscribe deliveries flake. The crate's `.config/nextest.toml` serializes `client_server` via the `serial-sd-port` test-group, so `cargo nextest run` (used by CI) gives stable results. For the legacy harness, pass `--test-threads=1`: `cargo test --test client_server -- --test-threads=1`.


## [0.6.0](https://github.com/luminartech/simple_someip/compare/v0.5.3...v0.6.0) - 2026-04-20
Expand Down
162 changes: 158 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading