diff options
author | Marcel Müller <m.mueller@ifm.com> | 2022-03-22 13:34:14 +0100 |
---|---|---|
committer | Marcel Müller <m.mueller@ifm.com> | 2022-03-22 14:16:16 +0100 |
commit | 67d222982b7388f4e4a80308c60947cda621dcc4 (patch) | |
tree | 4096b2ce5b4b8f6b4dd0838eeb80ef97636a5887 /crates | |
parent | 3d679e475b1068762ada3054b996e47d42c9b348 (diff) |
Make Address/Reply{Receiver,Sender} contravariant
Previously the 'Address Types' were covariant with their generic type T. This
means that rustc understood `PhantomData<T>` to be 'equivalent' in
subtyping to `T`. This has implications for auto traits like `Send` and
`Sync`, because this means that the `Address Types` only implement those
if `T` does as well! But this is overly restrictive, the 'Address Types'
never contain a `T`! Nor do they ever touch it, hence we are using
`fn(T)` to tell rustc that it should treat it in a contravariant
fashion, meaning that in this case it is not dependent on `T` and always
implements `Send/Sync`.
Additionally, static tests were added to ensure this in the future.
This also removes some unsafe code, which makes this crate once again
free from it! 🎉
Signed-off-by: Marcel Müller <m.mueller@ifm.com>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/core/tedge_api/src/address.rs | 35 |
1 files changed, 24 insertions, 11 deletions
diff --git a/crates/core/tedge_api/src/address.rs b/crates/core/tedge_api/src/address.rs index 577a35f8..25387d87 100644 --- a/crates/core/tedge_api/src/address.rs +++ b/crates/core/tedge_api/src/address.rs @@ -27,17 +27,10 @@ pub type MessageReceiver = tokio::sync::mpsc::Receiver<InternalMessage>; /// The `Address` instance can be used to send messages of several types, but each type has to be /// in `MB: MessageBundle`. pub struct Address<MB: ReceiverBundle> { - _pd: PhantomData<MB>, + _pd: PhantomData<fn(MB)>, sender: MessageSender, } -// implement Sync for Address for all ReceiverBundle types -// -// MessageSender is a tokio::sync::mpsc::Sender<InternalMessage>, which is sync, MB is never -// instantiated, so this is safe to implement -#[allow(unsafe_code)] -unsafe impl<MB: ReceiverBundle + Send> Sync for Address<MB> {} - impl<MB: ReceiverBundle> std::fmt::Debug for Address<MB> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(&format!("Address<{}>", std::any::type_name::<MB>())) @@ -103,7 +96,7 @@ impl<MB: ReceiverBundle> Address<MB> { #[derive(Debug)] pub struct ReplyReceiver<M> { - _pd: PhantomData<M>, + _pd: PhantomData<fn(M)>, reply_recv: tokio::sync::oneshot::Receiver<AnySendBox>, } @@ -120,7 +113,7 @@ impl<M: Message> ReplyReceiver<M> { #[derive(Debug)] pub struct ReplySender<M> { - _pd: PhantomData<M>, + _pd: PhantomData<fn(M)>, reply_sender: tokio::sync::oneshot::Sender<AnySendBox>, } @@ -180,7 +173,14 @@ macro_rules! make_receiver_bundle { #[cfg(test)] mod tests { - use crate::{make_receiver_bundle, plugin::Message, Address}; + use static_assertions::{assert_impl_all, assert_not_impl_any}; + + use crate::{ + address::{ReplyReceiver, ReplySender}, + make_receiver_bundle, + plugin::Message, + Address, + }; #[derive(Debug)] struct Foo; @@ -204,4 +204,17 @@ mod tests { addr.send(Foo); addr.send(Bar); } + + /////// Assert that types have the correct traits + + #[allow(dead_code)] + struct NotSync { + _pd: std::marker::PhantomData<*const ()>, + } + + assert_impl_all!(Address<FooBar>: Clone, Send, Sync); + + assert_not_impl_any!(NotSync: Send, Sync); + assert_impl_all!(ReplySender<NotSync>: Send, Sync); + assert_impl_all!(ReplyReceiver<NotSync>: Send, Sync); } |