phase 20e: consolidate handle traits into SharedHandle<T>#108
Conversation
Collapses the three near-identical handle traits introduced in
19f / 20b / 20c into a single generic trait pair:
pub trait SharedHandle<T: 'static>: Clone + 'static {
fn get(&self) -> &T;
}
pub trait WrappableSharedHandle<T: 'static>: SharedHandle<T> {
fn wrap(value: T) -> Self;
}
Two blanket impls cover the alloc and no-alloc paths:
impl<T: 'static> SharedHandle<T> for &'static T { ... }
impl<T: 'static> SharedHandle<T> for Arc<T> { ... } // alloc-gated
impl<T: 'static> WrappableSharedHandle<T> for Arc<T> { ... } // alloc-gated
Deleted (each was a slot-specific copy of this same shape):
- `SocketHandle` / `WrappableSocketHandle` (transport.rs).
- `SdStateHandle` / `WrappableSdStateHandle` (server/sd_state.rs).
- `EventPublisherHandle<R, S, H>` /
`WrappableEventPublisherHandle<R, S, H>` (server/event_publisher.rs).
- `StaticSocketHandle<T>` (the `&'static T` blanket impl
subsumes its only purpose: carrying the `'static` lifetime).
Net trait count: 6 + 1 wrapper struct → 2 traits. ~60% less
boilerplate across the three former trait modules.
`Server`'s three handle bounds become uniform:
- `H: SharedHandle<F::Socket>`
- `Hsd: SharedHandle<SdStateManager>`
- `Hep: SharedHandle<EventPublisher<R, S, H, F::Socket>>`
`EventPublisher` gains an explicit `T: TransportSocket`
parameter — the price of carrying `T` as a generic on
`SharedHandle<T>` rather than as an associated type. The
struct grows a `PhantomData<T>` field so the type parameter is
well-formed without affecting drop-check.
Method calls collapse to one name everywhere:
- `H::socket()` / `Hsd::sd_state()` / `Hep::publisher()` →
`.get()` (consistent across all three slot types).
Default type-param expressions adjust to spell the `T`:
- `Hep = Arc<EventPublisher<R, S, H, <F as TransportFactory>::Socket>>`.
Test type-aliases gain the new `T` slot:
- `tests/client_server.rs::TestEventPublisher`
- `event_publisher.rs::TestEventPublisher` (internal)
- The `AlwaysFailSocket` regression-test type alias.
Pure rename / shape-change patch — no behavior change. The
runtime behavior of every public API call is identical to
20d's; this is type-system tidying motivated by the adversarial
review.
Adversarial-review observations addressed:
- "Three near-identical handle traits is a code smell" — fixed.
- "We didn't generalize this into a single Shared<T> trait" —
done.
Trade-off accepted: `EventPublisher` signature widens from
`<R, S, H>` to `<R, S, H, T>`. The cost is one extra type
parameter at the EventPublisher layer; the win is removing six
trait definitions and one wrapper struct.
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
This PR consolidates the server-side “shared handle” abstractions into a single generic SharedHandle<T> / WrappableSharedHandle<T> pair, replacing the prior slot-specific handle traits and updating Server/EventPublisher generics and call sites to use a uniform .get() accessor.
Changes:
- Introduces
SharedHandle<T>+WrappableSharedHandle<T>with blanket impls for&'static Tand (alloc-gated)Arc<T>. - Updates
ServerandEventPublisherto use the unified handle traits (including wideningEventPublisherto carry an explicit socket type parameterT). - Adjusts test type aliases to the new
EventPublisher<..., T>signature.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
tests/client_server.rs |
Updates TestEventPublisher alias to include the new socket type parameter. |
src/transport.rs |
Adds SharedHandle<T>/WrappableSharedHandle<T> and removes SocketHandle/StaticSocketHandle boilerplate. |
src/server/sd_state.rs |
Removes SD-state-specific handle traits in favor of SharedHandle<SdStateManager>. |
src/server/mod.rs |
Updates Server bounds/defaults and replaces .socket()/.sd_state() call sites with .get(). |
src/server/event_publisher.rs |
Widens EventPublisher generics to include socket type T, switches to SharedHandle<T>, and removes publisher-specific handle traits. |
Comments suppressed due to low confidence (1)
src/transport.rs:892
- This module-level doc comment still mentions
SocketHandle, which was removed in favor ofSharedHandle<T>. Please update the list of traits/types covered bystd_handle_implsso it reflects the current handle traits (or drop theSocketHandlemention ifSharedHandleis now provided via blanket impls outside this module).
/// Default `std`-flavoured impls of [`E2ERegistryHandle`] /
/// [`InterfaceHandle`] / [`SocketHandle`] backed by
/// `std::sync::{Arc, Mutex, RwLock}`. Pure std — no tokio
/// dependency — so they live in the executor-agnostic transport
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| pub use subscription_manager::{SubscribeError, SubscriptionHandle, SubscriptionManager}; | ||
|
|
||
| pub use sd_state::{SdStateHandle, SdStateManager, WrappableSdStateHandle}; | ||
| pub use sd_state::SdStateManager; |
There was a problem hiding this comment.
With SdStateHandle/WrappableSdStateHandle no longer re-exported, please ensure any remaining doc comments in this module (or public docs) that reference those traits are updated to SharedHandle<SdStateManager> / WrappableSharedHandle<SdStateManager> to keep rustdoc accurate.
| H: SharedHandle<F::Socket>, | ||
| Hsd: SharedHandle<SdStateManager>, | ||
| Hep: SharedHandle<EventPublisher<R, S, H, F::Socket>>, |
There was a problem hiding this comment.
The ServerHandles section immediately above this bound still mentions the removed StaticSocketHandle/Wrappable*Handle traits. Please update that doc comment to describe the new SharedHandle<T> / WrappableSharedHandle<T> model and the no-alloc &'static T usage, so the docs match the new bounds here.
| Hep = Arc<EventPublisher<R, S, H, <F as TransportFactory>::Socket>>, | ||
| > where | ||
| R: E2ERegistryHandle, | ||
| S: SubscriptionHandle, | ||
| F: TransportFactory + 'static, | ||
| F::Socket: 'static, | ||
| Tm: Timer + Clone + 'static, | ||
| H: SocketHandle<Socket = F::Socket>, | ||
| Hsd: SdStateHandle, | ||
| Hep: EventPublisherHandle<R, S, H>, | ||
| H: SharedHandle<F::Socket>, | ||
| Hsd: SharedHandle<SdStateManager>, | ||
| Hep: SharedHandle<EventPublisher<R, S, H, F::Socket>>, |
There was a problem hiding this comment.
The field docs in this struct still reference StaticSocketHandle<T> and the old EventPublisher<R, S, H> 3-parameter shape. Since this struct now uses SharedHandle<F::Socket> and EventPublisher<R, S, H, F::Socket>, please update the nearby doc comments to reflect &'static T (no-alloc) and the new EventPublisher<..., T> signature.
| H: WrappableSharedHandle<F::Socket>, | ||
| Hsd: WrappableSharedHandle<SdStateManager>, | ||
| Hep: WrappableSharedHandle<EventPublisher<R, S, H, F::Socket>>, |
There was a problem hiding this comment.
This impl switches the bounds to WrappableSharedHandle<...>, but the method docs/comments in the same impl (e.g., new_with_deps) still refer to WrappableSocketHandle / SocketHandle and StaticSocketHandle. Please update that text so users reading the docs see the new WrappableSharedHandle/SharedHandle terminology.
| use crate::transport::{E2ERegistryHandle, SocketHandle, TransportSocket}; | ||
| #[cfg(any(feature = "embassy_channels", feature = "server"))] | ||
| use crate::transport::{E2ERegistryHandle, SharedHandle, TransportSocket}; | ||
| #[cfg(test)] |
There was a problem hiding this comment.
Arc is only used inside the #[cfg(all(test, feature = "server-tokio"))] test module below, but the import is gated with just #[cfg(test)]. This will produce an unused_imports warning when compiling unit tests without server-tokio enabled. Consider moving the Arc import into the test module or gating it with the same all(test, feature = "server-tokio") condition.
| #[cfg(test)] | |
| #[cfg(all(test, feature = "server-tokio"))] |
|
|
||
| pub use error::Error; | ||
| pub use event_publisher::{EventPublisher, EventPublisherHandle, WrappableEventPublisherHandle}; | ||
| pub use event_publisher::EventPublisher; |
There was a problem hiding this comment.
Now that EventPublisherHandle/WrappableEventPublisherHandle are no longer re-exported, there are still doc comments in this module that mention/link to EventPublisherHandle (e.g. the publisher() docs later in the file). Those references should be updated to the new SharedHandle<EventPublisher<...>> / Hep terminology to avoid stale docs and potential broken intra-doc links.
Collapses the three near-identical handle traits introduced in 19f / 20b / 20c into a single generic trait pair:
Two blanket impls cover the alloc and no-alloc paths:
Deleted (each was a slot-specific copy of this same shape):
SocketHandle/WrappableSocketHandle(transport.rs).SdStateHandle/WrappableSdStateHandle(server/sd_state.rs).EventPublisherHandle<R, S, H>/WrappableEventPublisherHandle<R, S, H>(server/event_publisher.rs).StaticSocketHandle<T>(the&'static Tblanket impl subsumes its only purpose: carrying the'staticlifetime).Net trait count: 6 + 1 wrapper struct → 2 traits. ~60% less boilerplate across the three former trait modules.
Server's three handle bounds become uniform:H: SharedHandle<F::Socket>Hsd: SharedHandle<SdStateManager>Hep: SharedHandle<EventPublisher<R, S, H, F::Socket>>EventPublishergains an explicitT: TransportSocketparameter — the price of carryingTas a generic onSharedHandle<T>rather than as an associated type. The struct grows aPhantomData<T>field so the type parameter is well-formed without affecting drop-check.Method calls collapse to one name everywhere:
H::socket()/Hsd::sd_state()/Hep::publisher()→.get()(consistent across all three slot types).Default type-param expressions adjust to spell the
T:Hep = Arc<EventPublisher<R, S, H, <F as TransportFactory>::Socket>>.Test type-aliases gain the new
Tslot:tests/client_server.rs::TestEventPublisherevent_publisher.rs::TestEventPublisher(internal)AlwaysFailSocketregression-test type alias.Pure rename / shape-change patch — no behavior change. The runtime behavior of every public API call is identical to 20d's; this is type-system tidying motivated by the adversarial review.
Adversarial-review observations addressed:
Trade-off accepted:
EventPublishersignature widens from<R, S, H>to<R, S, H, T>. The cost is one extra type parameter at the EventPublisher layer; the win is removing six trait definitions and one wrapper struct.Gates green: