proxima_primitives/sync/
mpsc.rs1#[cfg(feature = "std")]
59use futures::executor::block_on;
60
61#[derive(Debug, thiserror::Error)]
65#[error("send on closed channel")]
66pub struct SendError<T>(pub T);
67
68impl<T> SendError<T> {
69 pub fn into_inner(self) -> T {
70 self.0
71 }
72}
73
74#[derive(Debug, thiserror::Error)]
77pub enum TrySendError<T> {
78 #[error("channel full")]
80 Full(T),
81 #[error("channel closed")]
83 Closed(T),
84}
85
86impl<T> TrySendError<T> {
87 pub fn into_inner(self) -> T {
88 match self {
89 Self::Full(value) | Self::Closed(value) => value,
90 }
91 }
92}
93
94#[derive(Debug)]
97pub struct Sender<T> {
98 inner: async_channel::Sender<T>,
99}
100
101impl<T> Clone for Sender<T> {
102 fn clone(&self) -> Self {
103 Self {
104 inner: self.inner.clone(),
105 }
106 }
107}
108
109impl<T> Sender<T> {
110 pub async fn send(&self, value: T) -> Result<(), SendError<T>> {
113 self.inner
114 .send(value)
115 .await
116 .map_err(|error| SendError(error.0))
117 }
118
119 pub fn try_send(&self, value: T) -> Result<(), TrySendError<T>> {
121 match self.inner.try_send(value) {
122 Ok(()) => Ok(()),
123 Err(async_channel::TrySendError::Full(value)) => Err(TrySendError::Full(value)),
124 Err(async_channel::TrySendError::Closed(value)) => Err(TrySendError::Closed(value)),
125 }
126 }
127
128 pub fn is_closed(&self) -> bool {
129 self.inner.is_closed()
130 }
131
132 pub fn close(&self) -> bool {
134 self.inner.close()
135 }
136}
137
138#[derive(Debug)]
140pub struct Receiver<T> {
141 inner: async_channel::Receiver<T>,
142}
143
144impl<T> Receiver<T> {
145 pub async fn recv(&mut self) -> Option<T> {
148 self.inner.recv().await.ok()
149 }
150
151 #[cfg(all(feature = "std", not(target_family = "wasm")))]
153 pub fn recv_blocking(&self) -> Option<T> {
154 block_on(self.inner.recv()).ok()
155 }
156
157 pub fn close(&mut self) -> bool {
158 self.inner.close()
159 }
160}
161
162pub fn channel<T>(capacity: usize) -> (Sender<T>, Receiver<T>) {
164 let (sender, receiver) = async_channel::bounded(capacity.max(1));
165 (Sender { inner: sender }, Receiver { inner: receiver })
166}
167
168#[derive(Debug)]
171pub struct UnboundedSender<T> {
172 inner: async_channel::Sender<T>,
173}
174
175impl<T> Clone for UnboundedSender<T> {
176 fn clone(&self) -> Self {
177 Self {
178 inner: self.inner.clone(),
179 }
180 }
181}
182
183impl<T> UnboundedSender<T> {
184 pub fn send(&self, value: T) -> Result<(), SendError<T>> {
187 match self.inner.try_send(value) {
188 Ok(()) => Ok(()),
189 Err(async_channel::TrySendError::Closed(value)) => Err(SendError(value)),
190 Err(async_channel::TrySendError::Full(_)) => {
191 unreachable!("unbounded channel reported full")
192 }
193 }
194 }
195
196 pub fn is_closed(&self) -> bool {
197 self.inner.is_closed()
198 }
199}
200
201#[derive(Debug)]
204pub struct UnboundedReceiver<T> {
205 inner: async_channel::Receiver<T>,
206}
207
208impl<T> UnboundedReceiver<T> {
209 pub async fn recv(&mut self) -> Option<T> {
210 self.inner.recv().await.ok()
211 }
212
213 pub fn close(&mut self) -> bool {
214 self.inner.close()
215 }
216}
217
218pub fn unbounded_channel<T>() -> (UnboundedSender<T>, UnboundedReceiver<T>) {
220 let (sender, receiver) = async_channel::unbounded();
221 (
222 UnboundedSender { inner: sender },
223 UnboundedReceiver { inner: receiver },
224 )
225}
226
227#[cfg(all(test, not(loom)))]
233#[allow(clippy::unwrap_used, clippy::expect_used)]
234mod tests {
235 use super::*;
236 use futures::executor::block_on;
237
238 #[test]
239 fn bounded_send_recv_roundtrips() {
240 let (sender, mut receiver) = channel::<u32>(4);
241 block_on(async move {
242 sender.send(7).await.expect("send");
243 assert_eq!(receiver.recv().await, Some(7));
244 });
245 }
246
247 #[test]
248 fn bounded_try_send_returns_full_when_at_capacity() {
249 let (sender, _receiver) = channel::<u32>(1);
250 sender.try_send(1).expect("first slot");
251 match sender.try_send(2) {
252 Err(TrySendError::Full(value)) => assert_eq!(value, 2),
253 other => panic!("expected Full, got {other:?}"),
254 }
255 }
256
257 #[test]
258 fn bounded_send_returns_value_after_receiver_dropped() {
259 let (sender, receiver) = channel::<u32>(1);
260 drop(receiver);
261 block_on(async move {
262 match sender.send(9).await {
263 Err(error) => assert_eq!(error.into_inner(), 9),
264 Ok(()) => panic!("send to dropped receiver should error"),
265 }
266 });
267 }
268
269 #[test]
270 fn mpsc_sender_close_returns_pending_send_and_drains_accepted_values() {
271 let (sender, mut receiver) = channel::<u32>(1);
272 sender.try_send(11).expect("first value should be accepted");
273
274 block_on(async move {
275 let mut pending_send = core::pin::pin!(sender.send(22));
276 let first_poll = futures::future::poll_fn(|context| {
277 core::task::Poll::Ready(pending_send.as_mut().poll(context))
278 })
279 .await;
280 assert!(matches!(first_poll, core::task::Poll::Pending));
281
282 assert!(sender.close());
283 match pending_send.await {
284 Err(error) => assert_eq!(error.into_inner(), 22),
285 Ok(()) => panic!("close should return a send that was waiting for capacity"),
286 }
287 assert_eq!(receiver.recv().await, Some(11));
288 assert_eq!(receiver.recv().await, None);
289 });
290 }
291
292 #[test]
293 fn mpsc_receiver_blocking_drains_after_sender_close() {
294 let (sender, receiver) = channel::<u32>(1);
295 sender.try_send(31).expect("value should be accepted");
296 assert!(sender.close());
297 assert_eq!(receiver.recv_blocking(), Some(31));
298 assert_eq!(receiver.recv_blocking(), None);
299 }
300
301 #[test]
302 fn unbounded_send_recv_roundtrips() {
303 let (sender, mut receiver) = unbounded_channel::<u32>();
304 sender.send(42).expect("send");
305 block_on(async move {
306 assert_eq!(receiver.recv().await, Some(42));
307 });
308 }
309
310 #[test]
311 fn unbounded_send_returns_value_after_receiver_dropped() {
312 let (sender, receiver) = unbounded_channel::<u32>();
313 drop(receiver);
314 match sender.send(3) {
315 Err(error) => assert_eq!(error.into_inner(), 3),
316 Ok(()) => panic!("send to dropped receiver should error"),
317 }
318 }
319}