phase 20c: EventPublisherHandle trait + drop Arc<EventPublisher> requ…#106
Conversation
…irement Mirrors phase 20b's `SdStateHandle` work for the second of the two production-path Arc usages flagged by the 20-pre alloc audit (finding E.1). Adds: - `EventPublisherHandle<R, S, H>: Clone + 'static` trait in `src/server/event_publisher.rs`. Method: `fn publisher(&self) -> &EventPublisher<R, S, H>`. - `WrappableEventPublisherHandle<R, S, H>: EventPublisherHandle<...>` extension trait with `fn wrap(EventPublisher<R, S, H>) -> Self`. - `Arc<EventPublisher<R, S, H>>: EventPublisherHandle + WrappableEventPublisherHandle` (alloc-using std-side default; preserves existing behavior). - `&'static EventPublisher<R, S, H>: EventPublisherHandle` (no-alloc bare-metal path; user declares the static, supplies the reference into a future `Server::new_with_handles`). Server gains a third type parameter `Hep = Arc<EventPublisher<R, S, H>>` (default), threaded through the struct decl and all three impl blocks. Field `publisher: Arc<EventPublisher<R, S, H>>` becomes `publisher: Hep`. `Arc::new(EventPublisher::new(...))` in constructors becomes `Hep::wrap(EventPublisher::new(...))`. `Server::publisher()` accessor return type changes from `Arc<EventPublisher<R, S, H>>` to `Hep` — non-breaking for std users who pick up the default; bare-metal users get their chosen handle type back. Existing call sites pick up the `Hep` default; no churn in `tests/`, `examples/`, or any caller. All three Arc impls (SocketHandle, SdStateHandle, EventPublisherHandle) follow the same pattern: `Arc<T>` for std (alloc), `&'static T` for bare-metal (no-alloc), `Wrappable*` extension for the inline- construction path. Three of four remediation items in the 20-pre alloc audit are now done: the recv buffer (20a), `Arc<SdStateManager>` (20b), and `Arc<EventPublisher>` (20c). The last item — combining all three handle types into a single `Server::new_with_handles` constructor that accepts pre-built handles directly without the `wrap` step — lands in 20d. Type-signature width: Server now reads `Server<R, S, F, Tm, H = Arc<F::Socket>, Hsd = Arc<SdStateManager>, Hep = Arc<EventPublisher<R, S, H>>>`. Three defaults preserve every existing call site. After 20d, a bare-metal caller will spell out all three explicitly via the new constructor, and a std caller will keep accepting all three defaults via `Server::new_with_deps`. Gates green: - cargo fmt --check - cargo clippy --tests (2 pre-existing warnings, unrelated) - cargo build --workspace --all-targets - cargo build --no-default-features --features client,server,bare_metal - cargo build -p simple-someip-embassy-net --target thumbv7em-none-eabihf - cargo test --features client-tokio,server-tokio --test client_server -- --test-threads=1 (11/11) - cargo test --features client,server,bare_metal --test bare_metal_e2e (2/2) - cargo test -p simple-someip-embassy-net --test loopback (3/3) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Introduces a handle-indirection layer for the server’s EventPublisher, mirroring the existing SocketHandle / SdStateHandle pattern, to reduce hard dependency on Arc<EventPublisher<...>> and support no-alloc sharing strategies (e.g. &'static EventPublisher).
Changes:
- Added
EventPublisherHandle+WrappableEventPublisherHandletraits, with built-in implementations forArc<EventPublisher<...>>and&'static EventPublisher<...>. - Extended
Serverwith a new generic parameterHep(defaulting toArc<EventPublisher<...>>) and threaded it through constructors and impl blocks. - Updated
Server::publisher()to returnHep(the chosen handle type) instead of always returning anArc<...>.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/server/mod.rs | Adds Hep to Server generics, stores the publisher behind Hep, wraps construction via Hep::wrap, and returns Hep from publisher() |
| src/server/event_publisher.rs | Defines EventPublisherHandle / WrappableEventPublisherHandle and provides Arc / &'static implementations |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// run loop and any external task that wants to publish events | ||
| /// (`server.publisher().publish_event(...)`). Two impls ship out | ||
| /// of the box, mirroring the pattern established by |
There was a problem hiding this comment.
The docs/examples here assume callers can do server.publisher().publish_event(...), but Server::publisher() now returns the generic Hep handle and EventPublisherHandle does not require Deref<Target = EventPublisher<...>>. That call pattern only works for the built-in Arc<_> / &'static _ handles (via deref), and will not compile for other valid handle types. Consider updating the docs to show the trait-based access pattern (e.g., borrowing via EventPublisherHandle::publisher()), or alternatively add a Deref bound if direct method calls on the handle are intended to be a guaranteed API.
| /// run loop and any external task that wants to publish events | |
| /// (`server.publisher().publish_event(...)`). Two impls ship out | |
| /// of the box, mirroring the pattern established by | |
| /// run loop and any external task that wants to publish events. | |
| /// Callers should borrow the underlying publisher via | |
| /// [`EventPublisherHandle::publisher`] before invoking publisher | |
| /// methods (for example, | |
| /// `server.publisher().publisher().publish_event(...)`). Two impls | |
| /// ship out of the box, mirroring the pattern established by |
| /// Get a clone of the event-publisher handle for sending events. | ||
| /// | ||
| /// Returns the [`EventPublisherHandle`] type — `Arc<EventPublisher<R, | ||
| /// S, H>>` for std users (the default `Hep`), | ||
| /// `&'static EventPublisher<R, S, H>` for bare-metal-no-alloc. |
There was a problem hiding this comment.
This accessor returns the generic Hep handle, but the surrounding docs imply it can always be used directly for publishing events. Since EventPublisherHandle doesn’t require Deref<Target = EventPublisher<...>>, callers using a custom handle type may need to explicitly borrow the inner publisher via the handle trait method before calling publish_event/etc. Consider adjusting the docs to reflect the guaranteed usage pattern for all Hep implementations (or constrain Hep with Deref if the direct-call ergonomics are intended).
| /// Get a clone of the event-publisher handle for sending events. | |
| /// | |
| /// Returns the [`EventPublisherHandle`] type — `Arc<EventPublisher<R, | |
| /// S, H>>` for std users (the default `Hep`), | |
| /// `&'static EventPublisher<R, S, H>` for bare-metal-no-alloc. | |
| /// Get a clone of the configured event-publisher handle. | |
| /// | |
| /// This returns the generic handle type `Hep` implementing | |
| /// [`EventPublisherHandle`]. For the default handle types this is typically | |
| /// `Arc<EventPublisher<R, S, H>>` on `std` and | |
| /// `&'static EventPublisher<R, S, H>` on bare-metal-no-alloc. | |
| /// | |
| /// Callers using a custom `Hep` implementation should use the | |
| /// [`EventPublisherHandle`] trait to borrow/access the underlying | |
| /// [`EventPublisher`] before calling publisher methods such as | |
| /// `publish_event`. |
…irement
Mirrors phase 20b's
SdStateHandlework for the second of the two production-path Arc usages flagged by the 20-pre alloc audit (finding E.1). Adds:EventPublisherHandle<R, S, H>: Clone + 'statictrait insrc/server/event_publisher.rs. Method:fn publisher(&self) -> &EventPublisher<R, S, H>.WrappableEventPublisherHandle<R, S, H>: EventPublisherHandle<...>extension trait withfn wrap(EventPublisher<R, S, H>) -> Self.Arc<EventPublisher<R, S, H>>: EventPublisherHandle + WrappableEventPublisherHandle(alloc-using std-side default; preserves existing behavior).&'static EventPublisher<R, S, H>: EventPublisherHandle(no-alloc bare-metal path; user declares the static, supplies the reference into a futureServer::new_with_handles).Server gains a third type parameter
Hep = Arc<EventPublisher<R, S, H>>(default), threaded through the struct decl and all three impl blocks. Fieldpublisher: Arc<EventPublisher<R, S, H>>becomespublisher: Hep.Arc::new(EventPublisher::new(...))in constructors becomesHep::wrap(EventPublisher::new(...)).Server::publisher()accessor return type changes fromArc<EventPublisher<R, S, H>>toHep— non-breaking for std users who pick up the default; bare-metal users get their chosen handle type back.Existing call sites pick up the
Hepdefault; no churn intests/,examples/, or any caller. All three Arc impls (SocketHandle, SdStateHandle, EventPublisherHandle) follow the same pattern:Arc<T>for std (alloc),&'static Tfor bare-metal (no-alloc),Wrappable*extension for the inline- construction path.Three of four remediation items in the 20-pre alloc audit are now done: the recv buffer (20a),
Arc<SdStateManager>(20b), andArc<EventPublisher>(20c). The last item — combining all three handle types into a singleServer::new_with_handlesconstructor that accepts pre-built handles directly without thewrapstep — lands in 20d.Type-signature width: Server now reads
Server<R, S, F, Tm, H = Arc<F::Socket>, Hsd = Arc<SdStateManager>, Hep = Arc<EventPublisher<R, S, H>>>. Three defaults preserve every existing call site. After 20d, a bare-metal caller will spell out all three explicitly via the new constructor, and a std caller will keep accepting all three defaults viaServer::new_with_deps.Gates green: