thruput_testkit/
mailbox.rs1use std::collections::{HashMap, VecDeque};
10use std::sync::Arc;
11
12use tokio::sync::mpsc;
13use xdrs::ReadXDR;
14
15use crate::error::{Result, TestkitError};
16
17#[derive(Debug, Clone)]
19pub struct Envelope {
20 pub from: String,
22 pub bytes: Vec<u8>,
24}
25
26impl Envelope {
27 pub(crate) fn decode<T>(self) -> Result<Message<T>>
29 where
30 T: for<'r> ReadXDR<'r>,
31 {
32 let body = xdrs::cxs::decode::<T>(&self.bytes).map_err(TestkitError::decode)?;
33 Ok(Message {
34 from: self.from,
35 body,
36 })
37 }
38}
39
40#[derive(Debug, Clone)]
42pub struct Message<T> {
43 pub from: String,
45 pub body: T,
47}
48
49#[derive(Debug)]
56pub struct Mailbox {
57 name: Arc<str>,
58 inbox: mpsc::UnboundedReceiver<Envelope>,
59 peers: HashMap<String, mpsc::UnboundedSender<Envelope>>,
60 cache: VecDeque<Envelope>,
61}
62
63impl Mailbox {
64 pub(crate) fn new(
65 name: Arc<str>,
66 inbox: mpsc::UnboundedReceiver<Envelope>,
67 peers: HashMap<String, mpsc::UnboundedSender<Envelope>>,
68 ) -> Self {
69 Self {
70 name,
71 inbox,
72 peers,
73 cache: VecDeque::new(),
74 }
75 }
76
77 pub fn send_to(&self, to: &str, bytes: impl Into<Vec<u8>>) -> Result<()> {
82 let sender = self
83 .peers
84 .get(to)
85 .ok_or_else(|| TestkitError::UnknownAgent {
86 name: to.to_owned(),
87 })?;
88 sender
89 .send(Envelope {
90 from: self.name.to_string(),
91 bytes: bytes.into(),
92 })
93 .map_err(|_| TestkitError::MailboxClosed {
94 name: to.to_owned(),
95 })
96 }
97
98 pub async fn recv(&mut self) -> Option<Envelope> {
102 if let Some(envelope) = self.cache.pop_front() {
103 return Some(envelope);
104 }
105 self.inbox.recv().await
106 }
107
108 pub fn try_recv(&mut self) -> Option<Envelope> {
110 if let Some(envelope) = self.cache.pop_front() {
111 return Some(envelope);
112 }
113 self.inbox.try_recv().ok()
114 }
115
116 pub async fn recv_from_any(&mut self, from: &[&str]) -> Option<Envelope> {
123 if let Some(index) = self.cache.iter().position(|e| sender_in(from, e)) {
124 return self.cache.remove(index);
125 }
126 loop {
127 match self.inbox.recv().await {
128 Some(envelope) if sender_in(from, &envelope) => return Some(envelope),
129 Some(envelope) => self.cache.push_back(envelope),
130 None => return None,
131 }
132 }
133 }
134
135 pub fn try_recv_from_any(&mut self, from: &[&str]) -> Option<Envelope> {
138 if let Some(index) = self.cache.iter().position(|e| sender_in(from, e)) {
139 return self.cache.remove(index);
140 }
141 loop {
142 match self.inbox.try_recv() {
143 Ok(envelope) if sender_in(from, &envelope) => return Some(envelope),
144 Ok(envelope) => self.cache.push_back(envelope),
145 Err(_) => return None,
146 }
147 }
148 }
149
150 pub async fn recv_from(&mut self, from: &str) -> Option<Envelope> {
153 self.recv_from_any(&[from]).await
154 }
155
156 pub fn try_recv_from(&mut self, from: &str) -> Option<Envelope> {
158 self.try_recv_from_any(&[from])
159 }
160}
161
162fn sender_in(senders: &[&str], envelope: &Envelope) -> bool {
164 senders.iter().any(|s| envelope.from == *s)
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 fn envelope(from: &str, byte: u8) -> Envelope {
172 Envelope {
173 from: from.to_owned(),
174 bytes: vec![byte],
175 }
176 }
177
178 #[test]
179 fn recv_from_selects_a_sender_and_caches_the_rest() {
180 let (tx, rx) = mpsc::unbounded_channel();
181 let mut mailbox = Mailbox::new(Arc::from("bob"), rx, HashMap::new());
182
183 tx.send(envelope("alice", 1)).expect("send alice");
185 tx.send(envelope("carol", 2)).expect("send carol");
186
187 let carol = mailbox.try_recv_from("carol").expect("carol's message");
189 assert_eq!(carol.from, "carol");
190 assert_eq!(carol.bytes, vec![2]);
191
192 let alice = mailbox.try_recv().expect("alice's cached message");
194 assert_eq!(alice.from, "alice");
195 assert_eq!(alice.bytes, vec![1]);
196
197 assert!(mailbox.try_recv().is_none());
199 }
200
201 #[test]
202 fn recv_from_returns_none_when_no_matching_sender_remains() {
203 let (tx, rx) = mpsc::unbounded_channel();
204 let mut mailbox = Mailbox::new(Arc::from("bob"), rx, HashMap::new());
205
206 tx.send(envelope("alice", 1)).expect("send alice");
207
208 assert!(mailbox.try_recv_from("carol").is_none());
210 let alice = mailbox.try_recv().expect("alice's cached message");
211 assert_eq!(alice.from, "alice");
212 }
213
214 #[test]
215 fn recv_from_any_accepts_any_member_and_caches_outsiders() {
216 let (tx, rx) = mpsc::unbounded_channel();
217 let mut mailbox = Mailbox::new(Arc::from("admin"), rx, HashMap::new());
218
219 tx.send(envelope("stranger", 9)).expect("send stranger");
221 tx.send(envelope("bob", 2)).expect("send bob");
222 tx.send(envelope("alice", 1)).expect("send alice");
223
224 let first = mailbox
227 .try_recv_from_any(&["alice", "bob"])
228 .expect("first provider");
229 assert_eq!(first.from, "bob");
230 let second = mailbox
231 .try_recv_from_any(&["alice", "bob"])
232 .expect("second provider");
233 assert_eq!(second.from, "alice");
234
235 let stranger = mailbox.try_recv().expect("stranger's cached message");
237 assert_eq!(stranger.from, "stranger");
238 }
239}