Skip to main content

polybox_core/
message.rs

1use crate::*;
2use std::marker::PhantomData;
3
4/// A marker type for request messages.
5pub struct Request<T>(PhantomData<T>);
6
7/// A marker type for fire-and-forget messages.
8pub struct FireAndForget(());
9
10/// A trait for types that can be used to specify the kind of a [`Message`].
11///
12/// This trait is sealed and cannot be implemented outside of this crate.
13/// Use [`Request<T>`] or [`FireAndForget`] to specify the kind of a [`Message`].
14pub trait MessageSpecifier<T>: sealed::Sealed {
15    /// The output type of the message.
16    ///
17    /// This must implement [`MessageReply`], and is either [`Rx<T>`] for request
18    /// messages, or `()` for fire-and-forget messages.
19    type Output: MessageReply + Send;
20
21    /// The actual payload of the message.
22    ///
23    /// This is `T` for fire-and-forget messages, and `(T, Tx<R>)` for requests.
24    type Payload: Send + 'static;
25
26    /// Convert a message into its payload and output.
27    fn into_payload(msg: T) -> (Self::Payload, Self::Output);
28
29    /// Convert a payload back into the message.
30    fn from_payload(payload: Self::Payload) -> T;
31}
32
33impl<I: Send + 'static, R: Send + 'static> MessageSpecifier<I> for Request<R> {
34    type Output = Rx<R>;
35    type Payload = (I, Tx<R>);
36
37    fn into_payload(msg: I) -> (Self::Payload, Self::Output) {
38        let (tx, rx) = new_request();
39        ((msg, tx), rx)
40    }
41
42    fn from_payload(payload: Self::Payload) -> I {
43        let (msg, _tx) = payload;
44        msg
45    }
46}
47
48impl<I: Send + 'static> MessageSpecifier<I> for FireAndForget {
49    type Output = ();
50    type Payload = I;
51
52    fn into_payload(msg: I) -> (Self::Payload, Self::Output) {
53        (msg, ())
54    }
55
56    fn from_payload(payload: Self::Payload) -> I {
57        payload
58    }
59}
60
61/// A trait for types that can be used as the output of a [`Message`].
62///
63/// This trait is sealed and cannot be implemented outside of this crate.
64/// It is implemented for [`Rx<T>`] and `()`, which are the output types of
65/// request and fire-and-forget messages, respectively.
66pub trait MessageReply: Sized + sealed::Sealed {
67    /// The reply type of the message.
68    type Reply;
69
70    /// Receive the reply of the message.
71    fn receive(self) -> impl Future<Output = Result<Self::Reply, RxError>> + Send;
72
73    /// Same as [`Self::receive`], but blocks the current thread until the reply is received.
74    fn receive_blocking(self) -> Result<Self::Reply, RxError> {
75        futures::executor::block_on(self.receive())
76    }
77}
78
79impl MessageReply for () {
80    type Reply = ();
81
82    async fn receive(self) -> Result<Self::Reply, RxError> {
83        Ok(())
84    }
85}
86
87impl<T> MessageReply for Rx<T>
88where
89    T: Send + 'static,
90{
91    type Reply = T;
92
93    async fn receive(self) -> Result<Self::Reply, RxError> {
94        self.await
95    }
96}
97
98/// A trait that must be implemented for all types that are sent as messages.
99///
100/// It defines the kind of the message, which can be either [`Request<T>`] or [`FireAndForget`].
101pub trait Message: Send + 'static + Sized {
102    /// The kind of the message, which can be either [`Request<T>`] or [`FireAndForget`].
103    type Kind: MessageSpecifier<Self>;
104}
105
106/// A helper type for the output of a [`Message`].
107pub type Output<T> = <<T as Message>::Kind as MessageSpecifier<T>>::Output;
108
109/// A helper type for the reply of a [`Message`].
110pub type Reply<T> = <Output<T> as MessageReply>::Reply;
111
112/// A helper type for the payload of a [`Message`].
113pub type Payload<T> = <<T as Message>::Kind as MessageSpecifier<T>>::Payload;
114
115/// A trait that extends [`Message`] with some helper methods.
116pub trait MessageExt: Message {
117    fn build_payload(self) -> (Payload<Self>, Output<Self>)
118    where
119        Self: Sized,
120    {
121        <Self::Kind as MessageSpecifier<Self>>::into_payload(self)
122    }
123
124    fn destroy_payload(payload: Payload<Self>) -> Self
125    where
126        Self: Sized,
127    {
128        <Self::Kind as MessageSpecifier<Self>>::from_payload(payload)
129    }
130}
131impl<I> MessageExt for I where I: Message {}
132
133pub(crate) mod sealed {
134    pub trait Sealed {}
135
136    impl<T> Sealed for super::Request<T> {}
137    impl Sealed for super::FireAndForget {}
138
139    impl<T> Sealed for super::Rx<T> where T: Send + 'static {}
140    impl Sealed for () {}
141}
142
143//------------------------------------------------------------------------------------------------
144//  Message: Default implementations
145//------------------------------------------------------------------------------------------------
146
147macro_rules! implement_message_for_base_types {
148    ($(
149        $ty:ty
150    ),*) => {
151        $(
152            impl Message for $ty {
153                type Kind = FireAndForget;
154            }
155        )*
156    };
157}
158implement_message_for_base_types! {
159    u8, u16, u32, u64, u128,
160    i8, i16, i32, i64, i128,
161    (),
162    String, &'static str
163}
164
165macro_rules! implement_message_for_wrappers {
166    ($(
167        $wrapper:ty
168        $(where $_:ty: $where:ident)*
169    ,)*) => {
170        $(
171            impl<M> Message for $wrapper
172                where M: Send + 'static + $($where +)*
173            {
174                type Kind = FireAndForget;
175            }
176        )*
177    };
178}
179implement_message_for_wrappers!(
180    Box<M>,
181    std::sync::Arc<M> where M: Sync,
182    Vec<M>,
183    Box<[M]>,
184);
185
186macro_rules! implement_message_kind_and_message_for_tuples {
187    ($(
188        ($($id:ident: $na:ident + $na2:ident),*),
189    )*) => {
190        $(
191            impl<$($id),*> Message for ($($id,)*)
192            where
193                $($id: Message + Send + 'static,)*
194            {
195                type Kind = FireAndForget;
196            }
197        )*
198    };
199}
200implement_message_kind_and_message_for_tuples!(
201    (M1: m1 + m_1),
202    (M1: m1 + m_1, M2: m2 + m_2),
203    (M1: m1 + m_1, M2: m2 + m_2, M3: m3 + m_3),
204    (M1: m1 + m_1, M2: m2 + m_2, M3: m3 + m_3, M4: m4 + m_4),
205    (
206        M1: m1 + m_1,
207        M2: m2 + m_2,
208        M3: m3 + m_3,
209        M4: m4 + m_4,
210        M5: m5 + m_5
211    ),
212    (
213        M1: m1 + m_1,
214        M2: m2 + m_2,
215        M3: m3 + m_3,
216        M4: m4 + m_4,
217        M5: m5 + m_5,
218        M6: m6 + m_6
219    ),
220    (
221        M1: m1 + m_1,
222        M2: m2 + m_2,
223        M3: m3 + m_3,
224        M4: m4 + m_4,
225        M5: m5 + m_5,
226        M6: m6 + m_6,
227        M7: m7 + m_7
228    ),
229    (
230        M1: m1 + m_1,
231        M2: m2 + m_2,
232        M3: m3 + m_3,
233        M4: m4 + m_4,
234        M5: m5 + m_5,
235        M6: m6 + m_6,
236        M7: m7 + m_7,
237        M8: m8 + m_8
238    ),
239    (
240        M1: m1 + m_1,
241        M2: m2 + m_2,
242        M3: m3 + m_3,
243        M4: m4 + m_4,
244        M5: m5 + m_5,
245        M6: m6 + m_6,
246        M7: m7 + m_7,
247        M8: m8 + m_8,
248        M9: m9 + m_9
249    ),
250    (
251        M1: m1 + m_1,
252        M2: m2 + m_2,
253        M3: m3 + m_3,
254        M4: m4 + m_4,
255        M5: m5 + m_5,
256        M6: m6 + m_6,
257        M7: m7 + m_7,
258        M8: m8 + m_8,
259        M9: m9 + m_9,
260        M10: m10 + m_10
261    ),
262);