memfault_ssf/
msg_mailbox.rs

1//
2// Copyright (c) Memfault, Inc.
3// See License.txt for details
4use std::sync::mpsc::{channel, sync_channel, Receiver, Sender, SyncSender};
5
6use crate::{BoundedMailbox, BoundedTaskMailbox, Handler, Mailbox, MailboxError, Message, Service};
7
8/// A `MsgMailbox` only depends on the type of the messages it can contain.
9///
10/// This allows a real separation between the caller and the recipient, they do
11/// not need to know about each other.
12pub struct MsgMailbox<M: Message> {
13    service_mailbox: Box<dyn MsgMailboxT<M>>,
14}
15
16impl<M: Message> MsgMailbox<M> {
17    /// Create a mock msg mailbox. Messages will be kept in a Vec - Do not use this directly but use ServiceMock::new()
18    pub(super) fn mock() -> (Self, Receiver<M>) {
19        let (sender, receiver) = channel();
20        let mock = MockMsgMailbox::new(sender);
21        (
22            MsgMailbox {
23                service_mailbox: mock.duplicate(),
24            },
25            receiver,
26        )
27    }
28
29    /// Create a bounded mock msg mailbox. Messages will be kept in a Vec - Do not use this directly but use ServiceMock::new()
30    pub(super) fn bounded_mock(channel_size: usize) -> (Self, Receiver<M>) {
31        let (sender, receiver) = sync_channel(channel_size);
32        let mock = BoundedMockMsgMailbox::new(sender);
33        (
34            MsgMailbox {
35                service_mailbox: mock.duplicate(),
36            },
37            receiver,
38        )
39    }
40
41    pub fn send_and_forget(&self, message: M) -> Result<(), MailboxError> {
42        self.service_mailbox.send_and_forget(message)
43    }
44    pub fn send_and_wait_for_reply(&self, message: M) -> Result<M::Reply, MailboxError> {
45        self.service_mailbox.send_and_wait_for_reply(message)
46    }
47}
48
49impl<M: Message> Clone for MsgMailbox<M> {
50    fn clone(&self) -> Self {
51        MsgMailbox {
52            service_mailbox: self.service_mailbox.duplicate(),
53        }
54    }
55}
56
57trait MsgMailboxT<M: Message>: Send + Sync {
58    fn send_and_forget(&self, message: M) -> Result<(), MailboxError>;
59    fn send_and_wait_for_reply(&self, message: M) -> Result<M::Reply, MailboxError>;
60    fn duplicate(&self) -> Box<dyn MsgMailboxT<M>>;
61}
62
63impl<M, S> MsgMailboxT<M> for Mailbox<S>
64where
65    S: Service + 'static,
66    M: Message,
67    S: Handler<M>,
68{
69    fn send_and_forget(&self, message: M) -> Result<(), MailboxError> {
70        self.send_and_forget(message)
71    }
72    fn send_and_wait_for_reply(&self, message: M) -> Result<M::Reply, MailboxError> {
73        self.send_and_wait_for_reply(message)
74    }
75    fn duplicate(&self) -> Box<dyn MsgMailboxT<M>> {
76        Box::new(self.clone())
77    }
78}
79
80impl<M, S> MsgMailboxT<M> for BoundedMailbox<S>
81where
82    S: Service + 'static,
83    M: Message,
84    S: Handler<M>,
85{
86    fn send_and_forget(&self, message: M) -> Result<(), MailboxError> {
87        self.send_and_forget(message)
88    }
89    fn send_and_wait_for_reply(&self, message: M) -> Result<M::Reply, MailboxError> {
90        self.send_and_wait_for_reply(message)
91    }
92    fn duplicate(&self) -> Box<dyn MsgMailboxT<M>> {
93        Box::new(self.clone())
94    }
95}
96
97impl<M, S> MsgMailboxT<M> for BoundedTaskMailbox<S>
98where
99    S: Service + 'static,
100    M: Message,
101    S: Handler<M>,
102{
103    fn send_and_forget(&self, message: M) -> Result<(), MailboxError> {
104        self.send_and_forget(message)
105    }
106    fn send_and_wait_for_reply(&self, message: M) -> Result<M::Reply, MailboxError> {
107        self.send_and_wait_for_reply(message)
108    }
109    fn duplicate(&self) -> Box<dyn MsgMailboxT<M>> {
110        Box::new(self.clone())
111    }
112}
113
114impl<M, S> From<Mailbox<S>> for MsgMailbox<M>
115where
116    M: Message,
117    S: Service,
118    S: Handler<M>,
119    S: 'static,
120{
121    fn from(mailbox: Mailbox<S>) -> Self {
122        MsgMailbox {
123            service_mailbox: Box::new(mailbox),
124        }
125    }
126}
127
128impl<M, S> From<BoundedMailbox<S>> for MsgMailbox<M>
129where
130    M: Message,
131    S: Service,
132    S: Handler<M>,
133    S: 'static,
134{
135    fn from(mailbox: BoundedMailbox<S>) -> Self {
136        MsgMailbox {
137            service_mailbox: Box::new(mailbox),
138        }
139    }
140}
141
142impl<M, S> From<BoundedTaskMailbox<S>> for MsgMailbox<M>
143where
144    M: Message,
145    S: Service,
146    S: Handler<M>,
147    S: 'static,
148{
149    fn from(mailbox: BoundedTaskMailbox<S>) -> Self {
150        MsgMailbox {
151            service_mailbox: Box::new(mailbox),
152        }
153    }
154}
155
156pub(super) struct MockMsgMailbox<M> {
157    sender: Sender<M>,
158}
159
160impl<M> MockMsgMailbox<M> {
161    pub fn new(sender: Sender<M>) -> Self {
162        MockMsgMailbox { sender }
163    }
164}
165
166impl<M: Message> MsgMailboxT<M> for MockMsgMailbox<M> {
167    fn send_and_forget(&self, message: M) -> Result<(), MailboxError> {
168        if self.sender.send(message).is_err() {
169            return Err(MailboxError::SendChannelClosed);
170        }
171
172        Ok(())
173    }
174
175    fn send_and_wait_for_reply(&self, _message: M) -> Result<M::Reply, MailboxError> {
176        unimplemented!("We have not implemented send_and_wait_for_reply for MockMsgMailbox yet.")
177    }
178
179    fn duplicate(&self) -> Box<dyn MsgMailboxT<M>> {
180        Box::new(MockMsgMailbox {
181            sender: self.sender.clone(),
182        })
183    }
184}
185
186pub(super) struct BoundedMockMsgMailbox<M> {
187    sender: SyncSender<M>,
188}
189
190impl<M> BoundedMockMsgMailbox<M> {
191    pub fn new(sender: SyncSender<M>) -> Self {
192        BoundedMockMsgMailbox { sender }
193    }
194}
195
196impl<M: Message> MsgMailboxT<M> for BoundedMockMsgMailbox<M> {
197    fn send_and_forget(&self, message: M) -> Result<(), MailboxError> {
198        self.sender.try_send(message).map_err(|e| match e {
199            std::sync::mpsc::TrySendError::Full(_) => MailboxError::SendChannelFull,
200            std::sync::mpsc::TrySendError::Disconnected(_) => MailboxError::SendChannelClosed,
201        })
202    }
203
204    fn send_and_wait_for_reply(&self, _message: M) -> Result<M::Reply, MailboxError> {
205        unimplemented!(
206            "We have not implemented send_and_wait_for_reply for BoundedMockMsgMailbox yet."
207        )
208    }
209
210    fn duplicate(&self) -> Box<dyn MsgMailboxT<M>> {
211        Box::new(BoundedMockMsgMailbox {
212            sender: self.sender.clone(),
213        })
214    }
215}