summaryrefslogtreecommitdiffstats
path: root/crates
diff options
context:
space:
mode:
authorMarcel Müller <m.mueller@ifm.com>2022-03-22 13:34:14 +0100
committerMarcel Müller <m.mueller@ifm.com>2022-03-22 14:16:16 +0100
commit67d222982b7388f4e4a80308c60947cda621dcc4 (patch)
tree4096b2ce5b4b8f6b4dd0838eeb80ef97636a5887 /crates
parent3d679e475b1068762ada3054b996e47d42c9b348 (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.rs35
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);
}