Skip to main content

ntex_util/channel/
mpsc.rs

1//! A multi-producer, single-consumer, futures-aware, FIFO queue.
2use std::collections::VecDeque;
3use std::future::poll_fn;
4use std::{fmt, panic::UnwindSafe, pin::Pin, task::Context, task::Poll};
5
6use futures_core::{FusedStream, Stream};
7
8use super::cell::Cell;
9use crate::task::LocalWaker;
10
11/// Creates an unbounded in-memory channel.
12pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
13    let shared = Cell::new(Shared {
14        has_receiver: true,
15        buffer: VecDeque::new(),
16        blocked_recv: LocalWaker::new(),
17        closed: LocalWaker::new(),
18    });
19    let sender = Sender {
20        shared: shared.clone(),
21    };
22    let receiver = Receiver { shared };
23    (sender, receiver)
24}
25
26#[derive(Debug)]
27struct Shared<T> {
28    buffer: VecDeque<T>,
29    blocked_recv: LocalWaker,
30    closed: LocalWaker,
31    has_receiver: bool,
32}
33
34impl<T> Shared<T> {
35    fn close(&mut self) {
36        self.has_receiver = false;
37        self.blocked_recv.wake();
38        self.closed.wake();
39    }
40}
41
42/// The transmission end of a channel.
43///
44/// This is created by the `channel` function.
45#[derive(Debug)]
46pub struct Sender<T> {
47    shared: Cell<Shared<T>>,
48}
49
50impl<T> Unpin for Sender<T> {}
51
52impl<T> Sender<T> {
53    /// Sends the provided message along this channel.
54    pub fn send(&self, item: T) -> Result<(), SendError<T>> {
55        let shared = self.shared.get_mut();
56        if !shared.has_receiver {
57            return Err(SendError(item)); // receiver was dropped
58        }
59        shared.buffer.push_back(item);
60        shared.blocked_recv.wake();
61        Ok(())
62    }
63
64    /// Closes the channel for every sender.
65    ///
66    /// This prevents any further messages from being sent on the channel, by
67    /// this sender or any of its clones, while still enabling the receiver to
68    /// drain messages that are buffered.
69    pub fn close(&self) {
70        self.shared.get_mut().close();
71    }
72
73    /// Returns `true` if the channel is closed or the receiver has been dropped.
74    pub fn is_closed(&self) -> bool {
75        self.shared.strong_count() == 1 || !self.shared.get_ref().has_receiver
76    }
77
78    /// Polls whether the channel is closed or the receiver has been dropped.
79    ///
80    /// Only the task from the most recent call is woken, across this sender
81    /// and all of its clones.
82    pub fn poll_closed(&self, cx: &mut Context<'_>) -> Poll<()> {
83        let shared = self.shared.get_mut();
84        if shared.has_receiver {
85            shared.closed.register(cx.waker());
86            Poll::Pending
87        } else {
88            Poll::Ready(())
89        }
90    }
91
92    /// Waits until the channel is closed or the receiver has been dropped.
93    ///
94    /// See [`poll_closed`](Self::poll_closed).
95    pub async fn closed(&self) {
96        poll_fn(|cx| self.poll_closed(cx)).await;
97    }
98}
99
100impl<T> Clone for Sender<T> {
101    fn clone(&self) -> Self {
102        Sender {
103            shared: self.shared.clone(),
104        }
105    }
106}
107
108impl<T> Drop for Sender<T> {
109    fn drop(&mut self) {
110        let count = self.shared.strong_count();
111        let shared = self.shared.get_mut();
112
113        // check is last sender is about to drop
114        if shared.has_receiver && count == 2 {
115            // Wake up receiver as its stream has ended
116            shared.blocked_recv.wake();
117        }
118    }
119}
120
121/// The receiving end of a channel which implements the `Stream` trait.
122///
123/// This is created by the `channel` function.
124#[derive(Debug)]
125pub struct Receiver<T> {
126    shared: Cell<Shared<T>>,
127}
128
129impl<T> Receiver<T> {
130    /// Creates an additional sender for this channel.
131    pub fn sender(&self) -> Sender<T> {
132        Sender {
133            shared: self.shared.clone(),
134        }
135    }
136
137    /// Closes the receiving half of a channel, without dropping it.
138    ///
139    /// This prevents any further messages from being sent on the channel
140    /// while still enabling the receiver to drain messages that are buffered.
141    pub fn close(&self) {
142        self.shared.get_mut().close();
143    }
144
145    /// Returns whether this channel is closed.
146    pub fn is_closed(&self) -> bool {
147        self.shared.strong_count() == 1 || !self.shared.get_ref().has_receiver
148    }
149
150    /// Waits for the next message.
151    ///
152    /// Returns `None` once the channel is closed or every sender has been
153    /// dropped, and every buffered message has been received.
154    pub async fn recv(&self) -> Option<T> {
155        poll_fn(|cx| self.poll_recv(cx)).await
156    }
157
158    /// Polls for the next message.
159    ///
160    /// Returns `Ready(None)` once the channel is closed or every sender has
161    /// been dropped, and every buffered message has been received.
162    pub fn poll_recv(&self, cx: &mut Context<'_>) -> Poll<Option<T>> {
163        let shared = self.shared.get_mut();
164
165        if let Some(msg) = shared.buffer.pop_front() {
166            Poll::Ready(Some(msg))
167        } else if shared.has_receiver {
168            shared.blocked_recv.register(cx.waker());
169            if self.shared.strong_count() == 1 {
170                // All senders have been dropped, so drain the buffer and end the
171                // stream.
172                Poll::Ready(None)
173            } else {
174                Poll::Pending
175            }
176        } else {
177            Poll::Ready(None)
178        }
179    }
180}
181
182impl<T> Unpin for Receiver<T> {}
183
184impl<T> Stream for Receiver<T> {
185    type Item = T;
186
187    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
188        self.poll_recv(cx)
189    }
190}
191
192impl<T> FusedStream for Receiver<T> {
193    /// Returns `true` once the channel is closed and every buffered message
194    /// has been received.
195    fn is_terminated(&self) -> bool {
196        self.is_closed() && self.shared.get_ref().buffer.is_empty()
197    }
198}
199
200impl<T> UnwindSafe for Receiver<T> {}
201
202impl<T> Drop for Receiver<T> {
203    fn drop(&mut self) {
204        let shared = self.shared.get_mut();
205        shared.has_receiver = false;
206        let buffer = std::mem::take(&mut shared.buffer);
207        shared.closed.wake();
208
209        // queued messages may send on this channel from their `Drop`
210        drop(buffer);
211    }
212}
213
214/// Error type for sending, used when the receiving end of a channel is
215/// dropped
216pub struct SendError<T>(T);
217
218impl<T> std::error::Error for SendError<T> {}
219
220impl<T> fmt::Debug for SendError<T> {
221    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
222        fmt.debug_tuple("SendError").field(&"...").finish()
223    }
224}
225
226impl<T> fmt::Display for SendError<T> {
227    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
228        write!(fmt, "send failed because receiver is gone")
229    }
230}
231
232impl<T> SendError<T> {
233    /// Returns the message that was attempted to be sent but failed.
234    pub fn into_inner(self) -> T {
235        self.0
236    }
237}
238
239#[cfg(test)]
240mod tests {
241    use super::*;
242    use crate::{future::lazy, future::stream_recv};
243
244    /// STATEMENT: MPSC sender clones share delivery and closure state.
245    ///
246    /// HOW:
247    /// - Send from original and cloned handles and verify an empty live channel remains pending.
248    /// - Close or drop endpoints, check failed sends, and recover the value from `SendError`.
249    #[ntex::test]
250    async fn test_mpsc() {
251        let (tx, mut rx) = channel();
252        assert!(format!("{tx:?}").contains("Sender"));
253        assert!(format!("{rx:?}").contains("Receiver"));
254
255        tx.send("test").unwrap();
256        assert_eq!(stream_recv(&mut rx).await.unwrap(), "test");
257
258        let tx2 = tx.clone();
259        tx2.send("test2").unwrap();
260        assert_eq!(stream_recv(&mut rx).await.unwrap(), "test2");
261
262        assert_eq!(
263            lazy(|cx| Pin::new(&mut rx).poll_next(cx)).await,
264            Poll::Pending
265        );
266        drop(tx2);
267        assert_eq!(
268            lazy(|cx| Pin::new(&mut rx).poll_next(cx)).await,
269            Poll::Pending
270        );
271        drop(tx);
272
273        let (tx, mut rx) = channel::<String>();
274        tx.close();
275        assert_eq!(stream_recv(&mut rx).await, None);
276
277        let (tx, rx) = channel();
278        tx.send("test").unwrap();
279        drop(rx);
280        assert!(tx.send("test").is_err());
281
282        let (tx, _) = channel();
283        let tx2 = tx.clone();
284        tx.close();
285        assert!(tx.send("test").is_err());
286        assert!(tx2.send("test").is_err());
287
288        let err = SendError("test");
289        assert!(format!("{err:?}").contains("SendError"));
290        assert!(format!("{err}").contains("send failed because receiver is gone"));
291        assert_eq!(err.into_inner(), "test");
292    }
293
294    /// STATEMENT: Explicit closure wakes receivers, while sender exhaustion can be reversed.
295    ///
296    /// HOW:
297    /// - Close from each endpoint and check closed, terminated, and registered-waker state.
298    /// - Drop the last sender, then create one through the receiver and check the channel reopens.
299    #[ntex::test]
300    async fn test_close() {
301        let (tx, rx) = channel::<()>();
302        assert!(!tx.is_closed());
303        assert!(!rx.is_closed());
304        assert!(!rx.is_terminated());
305
306        tx.close();
307        assert!(tx.is_closed());
308        assert!(rx.is_closed());
309        assert!(rx.is_terminated());
310
311        let (tx, rx) = channel::<()>();
312        assert_eq!(lazy(|cx| rx.poll_recv(cx)).await, Poll::Pending);
313        assert!(rx.shared.get_ref().blocked_recv.is_set());
314        rx.close();
315        assert!(tx.is_closed());
316        assert!(!rx.shared.get_ref().blocked_recv.is_set());
317        assert_eq!(lazy(|cx| rx.poll_recv(cx)).await, Poll::Ready(None));
318
319        let (tx, rx) = channel::<()>();
320        drop(tx);
321        assert!(rx.is_closed());
322        assert!(rx.is_terminated());
323        let _tx = rx.sender();
324        assert!(!rx.is_closed());
325        assert!(!rx.is_terminated());
326    }
327
328    /// STATEMENT: Sender closure waiters complete when either endpoint closes the channel.
329    ///
330    /// HOW:
331    /// - Register closure waiters before receiver drop, receiver close, and sender close.
332    /// - Verify stored wakers are consumed and closure futures complete for cloned handles too.
333    #[ntex::test]
334    async fn test_poll_closed() {
335        let (tx, rx) = channel::<()>();
336        assert_eq!(lazy(|cx| tx.poll_closed(cx)).await, Poll::Pending);
337        assert!(tx.shared.get_ref().closed.is_set());
338        drop(rx);
339        assert!(!tx.shared.get_ref().closed.is_set());
340        assert_eq!(lazy(|cx| tx.poll_closed(cx)).await, Poll::Ready(()));
341        tx.closed().await;
342
343        let (tx, rx) = channel::<()>();
344        assert_eq!(lazy(|cx| tx.poll_closed(cx)).await, Poll::Pending);
345        rx.close();
346        assert!(!tx.shared.get_ref().closed.is_set());
347        tx.closed().await;
348
349        let (tx, _rx) = channel::<()>();
350        let tx2 = tx.clone();
351        assert_eq!(lazy(|cx| tx2.poll_closed(cx)).await, Poll::Pending);
352        tx.close();
353        assert!(!tx.shared.get_ref().closed.is_set());
354        tx2.closed().await;
355    }
356
357    /// STATEMENT: Dropping an MPSC receiver safely rejects reentrant sends from message destructors.
358    ///
359    /// HOW:
360    /// - Queue four values whose destructors attempt another send and count all drops.
361    /// - Drop the receiver and verify eight drops and a closed sender.
362    #[test]
363    fn test_drop_receiver_reentrant_send() {
364        use std::rc::Rc;
365
366        struct Msg(Option<Sender<Msg>>, Rc<std::cell::Cell<usize>>);
367
368        impl Drop for Msg {
369            fn drop(&mut self) {
370                self.1.set(self.1.get() + 1);
371                if let Some(tx) = self.0.take() {
372                    assert!(tx.send(Msg(None, self.1.clone())).is_err());
373                }
374            }
375        }
376
377        let drops = Rc::new(std::cell::Cell::new(0));
378        let (tx, rx) = channel();
379        for _ in 0..4 {
380            tx.send(Msg(Some(tx.clone()), drops.clone())).unwrap();
381        }
382        drop(rx);
383        assert_eq!(drops.get(), 8);
384        assert!(tx.is_closed());
385    }
386
387    /// STATEMENT: A closed MPSC stream is terminated only after its buffered messages are drained.
388    ///
389    /// HOW:
390    /// - Queue values, drop the sender, and check ordered delivery before termination.
391    /// - Repeat with explicit receiver closure and verify the queued value remains readable.
392    #[ntex::test]
393    async fn test_fused_drains_buffer() {
394        let (tx, mut rx) = channel();
395        tx.send(1).unwrap();
396        tx.send(2).unwrap();
397        drop(tx);
398
399        assert!(!rx.is_terminated());
400        assert_eq!(stream_recv(&mut rx).await, Some(1));
401        assert_eq!(stream_recv(&mut rx).await, Some(2));
402        assert!(rx.is_terminated());
403        assert_eq!(stream_recv(&mut rx).await, None);
404
405        let (tx, mut rx) = channel();
406        tx.send(1).unwrap();
407        rx.close();
408        assert!(!rx.is_terminated());
409        assert_eq!(stream_recv(&mut rx).await, Some(1));
410        assert!(rx.is_terminated());
411    }
412
413    /// STATEMENT: Direct MPSC receive returns a sent value and then ends after sender drop.
414    ///
415    /// HOW:
416    /// - Send and receive one value, drop the sender, and verify the next receive returns `None`.
417    #[ntex::test]
418    async fn test_mpsc_recv() {
419        let (tx, rx) = channel();
420        tx.send(1).unwrap();
421        assert_eq!(rx.recv().await, Some(1));
422        drop(tx);
423        assert_eq!(rx.recv().await, None);
424    }
425}