meslin/dynamic/
sender.rs

1use crate::*;
2use ::type_sets::{Contains, Members, SubsetOf};
3use futures::{future::BoxFuture, Future};
4use std::{
5    any::{type_name, Any, TypeId},
6    fmt::Debug,
7    marker::PhantomData,
8};
9
10/// A macro that defines a [`struct@DynSender`].
11///
12/// Example:
13/// - `DynSender![u32, u64]` == `DynSender<Set![u32, u64]>` == `DynSender<dyn Two<u32, u64>>`
14/// - `DynSender![]` == `DynSender<Set![]>` == `DynSender<dyn Empty>`
15#[macro_export]
16macro_rules! DynSender {
17    ($($tt:tt)*) => {
18        $crate::DynSender::<$crate::Set![$($tt)*]>
19    };
20}
21
22/// A wrapper around a [`Box<dyn DynSends>`](DynSends) that allows for type-checked conversions.
23///
24/// Any sender can be converted into a `DynSender`, as long as the protocol it sends implements
25/// [`trait@DynFromInto`] and marker traits [`AsSet`](type_sets::AsSet). This conversion is type-checked, so that
26/// it is impossible to create [`struct@DynSender`]s that send messages not accepted by the protocol.
27///
28/// ## Sending
29/// A [`struct@DynSender`] automatically implements [`Sends<M>`] for all messages `M` accepted by the
30/// protocol. This means that you can just use a [`struct@DynSender`] instead of a statically typed sender in
31/// most cases. If you need to send a message that is not accepted by the protocol, you can use the
32/// `dyn_{...}`-send methods, which return an error if the message is not accepted.
33///
34/// ## Generics
35/// The parameter `A` specifies the accepted messages of the dynamic sender. It can be specified
36/// using the [`macro@Set`] or the [`macro@DynSender`] macros:
37/// - `DynSender<Set![]>` == `DynSender![]`
38/// - `DynSender<Set![Msg1, Msg2]>` == `DynSender![Msg1, Msg2]`
39///
40/// ## Unchecked methods
41/// The unchecked methods, **not** marked unsafe, allow creating of `DynSender`s that send messages
42/// not accepted by the protocol. Only use these methods if you are sure that the protocol accepts
43/// the messages you send. If you are not sure, use the `try_transform` methods instead, which
44/// return an error if the protocol does not accept the messages.
45pub struct DynSender<A, W = ()> {
46    sender: BoxedSender<W>,
47    t: PhantomData<fn() -> A>,
48}
49
50impl<A, W> DynSender<A, W> {
51    /// Create a new `DynSender` from a statically typed sender.
52    pub fn new<S>(sender: S) -> Self
53    where
54        S: SendsProtocol + DynSends<With = W>,
55        A: SubsetOf<S::Protocol>,
56    {
57        Self::new_unchecked(sender)
58    }
59
60    /// Create a new `DynSender` from a statically typed sender, without checking if the protocol
61    /// accepts the messages.
62    pub fn new_unchecked<S>(sender: S) -> Self
63    where
64        S: DynSends<With = W>,
65    {
66        Self::from_boxed_unchecked(Box::new(sender))
67    }
68
69    /// Transform the `DynSender` into a `DynSender` that accepts a subset of the messages.
70    pub fn transform<A2>(self) -> DynSender<A2, W>
71    where
72        A2: SubsetOf<A>,
73    {
74        DynSender::from_boxed_unchecked(self.sender)
75    }
76
77    /// Attempt to transform the `DynSender` into a `DynSender` that accepts a subset of the messages,
78    /// failing if the protocol does not accept the messages.
79    pub fn try_transform<A2>(self) -> Result<DynSender<A2, W>, Self>
80    where
81        A2: Members,
82        W: 'static,
83        A: 'static,
84    {
85        if A2::members().iter().all(|t2| self.members().contains(t2)) {
86            Ok(DynSender::from_boxed_unchecked(self.sender))
87        } else {
88            Err(self)
89        }
90    }
91
92    /// Transform the `DynSender` into a `DynSender` that accepts a subset of the messages, without
93    /// checking if the protocol accepts the messages.
94    pub fn transform_unchecked<A2>(self) -> DynSender<A2, W> {
95        DynSender::from_boxed_unchecked(self.sender)
96    }
97
98    /// Convert a [`Box<dyn DynSends>`](DynSends) into a `DynSender`, without checking if the protocol
99    /// accepts the messages.
100    pub fn from_boxed_unchecked(sender: BoxedSender<W>) -> Self {
101        Self {
102            sender,
103            t: PhantomData,
104        }
105    }
106
107    /// Convert into a [`Box<dyn DynSends>`](DynSends).
108    pub fn into_boxed_sender(self) -> BoxedSender<W> {
109        self.sender
110    }
111
112    /// Downcast the inner sender to a statically typed sender.
113    pub fn downcast_ref<S>(&self) -> Option<&S>
114    where
115        S: IsSender<With = W> + 'static,
116        W: 'static,
117    {
118        self.sender.as_any().downcast_ref::<S>()
119    }
120}
121
122impl<A, W> IsSender for DynSender<A, W> {
123    type With = W;
124
125    fn is_closed(&self) -> bool {
126        self.sender.is_closed()
127    }
128
129    fn capacity(&self) -> Option<usize> {
130        self.sender.capacity()
131    }
132
133    fn len(&self) -> usize {
134        self.sender.len()
135    }
136
137    fn receiver_count(&self) -> usize {
138        self.sender.receiver_count()
139    }
140
141    fn sender_count(&self) -> usize {
142        self.sender.sender_count()
143    }
144}
145
146impl<A, W> DynSends for DynSender<A, W>
147where
148    A: 'static,
149    W: 'static,
150{
151    fn dyn_send_boxed_msg_with(
152        &self,
153        msg: BoxedMsg<Self::With>,
154    ) -> BoxFuture<Result<(), DynSendError<BoxedMsg<Self::With>>>> {
155        self.sender.dyn_send_boxed_msg_with(msg)
156    }
157
158    fn dyn_send_boxed_msg_blocking_with(
159        &self,
160        msg: BoxedMsg<Self::With>,
161    ) -> Result<(), DynSendError<BoxedMsg<Self::With>>> {
162        self.sender.dyn_send_boxed_msg_blocking_with(msg)
163    }
164
165    fn dyn_try_send_boxed_msg_with(
166        &self,
167        msg: BoxedMsg<Self::With>,
168    ) -> Result<(), DynTrySendError<BoxedMsg<Self::With>>> {
169        self.sender.dyn_try_send_boxed_msg_with(msg)
170    }
171
172    fn members(&self) -> &'static [TypeId] {
173        self.sender.members()
174    }
175
176    fn clone_boxed(&self) -> BoxedSender<Self::With> {
177        self.sender.clone_boxed()
178    }
179
180    fn as_any(&self) -> &dyn Any {
181        self.sender.as_any()
182    }
183}
184
185impl<A, W, M> Sends<M> for DynSender<A, W>
186where
187    A: Contains<M>,
188    M: Send + 'static,
189    W: Send + 'static,
190{
191    fn send_msg_with(
192        this: &Self,
193        msg: M,
194        with: Self::With,
195    ) -> impl Future<Output = Result<(), SendError<(M, Self::With)>>> + Send {
196        let fut = this.sender.dyn_send_msg_with(msg, with);
197        async {
198            match fut.await {
199                Ok(()) => Ok(()),
200                Err(e) => Err(match e {
201                    DynSendError::NotAccepted(_e) => {
202                        panic!("Message not accepted: {}", type_name::<(M, Self::With)>())
203                    }
204                    DynSendError::Closed((msg, with)) => SendError((msg, with)),
205                }),
206            }
207        }
208    }
209
210    fn try_send_msg_with(
211        this: &Self,
212        msg: M,
213        with: Self::With,
214    ) -> Result<(), TrySendError<(M, Self::With)>> {
215        match this.sender.dyn_try_send_msg_with(msg, with) {
216            Ok(()) => Ok(()),
217            Err(e) => Err(match e {
218                DynTrySendError::NotAccepted(_e) => {
219                    panic!("Message not accepted: {}", type_name::<(M, Self::With)>())
220                }
221                DynTrySendError::Closed((msg, with)) => TrySendError::Closed((msg, with)),
222                DynTrySendError::Full((msg, with)) => TrySendError::Full((msg, with)),
223            }),
224        }
225    }
226}
227
228impl<A, W: Debug> Debug for DynSender<A, W> {
229    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
230        f.debug_struct("DynSender")
231            .field("sender", &"...")
232            .field("t", &type_name::<A>())
233            .finish()
234    }
235}
236
237impl<A, W: 'static> Clone for DynSender<A, W> {
238    fn clone(&self) -> Self {
239        Self {
240            sender: self.sender.clone(),
241            t: PhantomData,
242        }
243    }
244}