Skip to main content

commonware_utils/channel/
ring.rs

1//! A bounded mpsc channel that drops the oldest item when full instead of applying backpressure.
2//!
3//! This is useful for scenarios where you want to keep the most recent items and can
4//! tolerate losing older ones, such as real-time data streams or status updates where
5//! only the latest values matter.
6//!
7//! # Example
8//!
9//! ```
10//! use futures::executor::block_on;
11//! use futures::{SinkExt, StreamExt};
12//! use commonware_utils::{NZUsize, channel::ring};
13//!
14//! block_on(async {
15//!     let (mut sender, mut receiver) = ring::channel::<u32>(NZUsize!(2));
16//!
17//!     // Fill the channel
18//!     sender.send(1).await.unwrap();
19//!     sender.send(2).await.unwrap();
20//!
21//!     // This will drop the oldest item (1) and insert 3
22//!     sender.send(3).await.unwrap();
23//!
24//!     // Receive the remaining items
25//!     assert_eq!(receiver.next().await, Some(2));
26//!     assert_eq!(receiver.next().await, Some(3));
27//! });
28//! ```
29
30use crate::sync::Mutex;
31use core::num::NonZeroUsize;
32use futures::{Sink, Stream, stream::FusedStream};
33use std::{
34    collections::VecDeque,
35    mem,
36    pin::Pin,
37    sync::Arc,
38    task::{Context, Poll, Waker},
39};
40use thiserror::Error;
41
42/// Error returned when sending to a channel whose receiver has been dropped.
43#[derive(Debug, Error)]
44#[error("channel closed")]
45pub struct ChannelClosed;
46
47/// Error returned by [`Receiver::try_recv`].
48#[derive(Debug, Error, PartialEq, Eq)]
49pub enum TryRecvError {
50    /// The channel currently has no buffered items, but senders still exist.
51    #[error("channel empty")]
52    Empty,
53    /// The channel is empty and all senders have been dropped.
54    #[error("channel closed")]
55    Disconnected,
56}
57
58/// State shared by the senders and the receiver of a channel.
59///
60/// Never drop items or run waker callbacks while holding the mutex protecting this state.
61/// They can drop a [Sender], which tries to take the same lock and deadlocks.
62#[derive(Debug)]
63struct Shared<T> {
64    buffer: VecDeque<T>,
65    capacity: usize,
66    receiver_waker: Option<Waker>,
67    sender_count: usize,
68    receiver_dropped: bool,
69}
70
71/// The sending half of a ring channel.
72///
73/// Implements [`Sink`] for sending items. Use [`SinkExt::send`](futures::SinkExt::send)
74/// to send items asynchronously.
75///
76/// This type can be cloned to create multiple producers for the same channel.
77/// The channel remains open until all senders are dropped.
78#[derive(Debug)]
79pub struct Sender<T> {
80    shared: Arc<Mutex<Shared<T>>>,
81}
82
83impl<T> Sender<T> {
84    /// Returns whether the receiver has been dropped.
85    ///
86    /// If this returns `true`, subsequent sends will fail with [`ChannelClosed`].
87    pub fn is_closed(&self) -> bool {
88        let shared = self.shared.lock();
89        shared.receiver_dropped
90    }
91
92    /// Sends an item, dropping the oldest buffered item if the channel is full.
93    ///
94    /// Returns `false` once the receiver has been dropped.
95    pub fn send_lossy(&self, item: T) -> bool {
96        let mut shared = self.shared.lock();
97
98        // Nothing will ever read a buffered item once the receiver is gone.
99        if shared.receiver_dropped {
100            return false;
101        }
102
103        // Make room by evicting the oldest item rather than blocking the sender.
104        let old_item = if shared.buffer.len() >= shared.capacity {
105            shared.buffer.pop_front()
106        } else {
107            None
108        };
109
110        // Buffer the item and take the receiver's waker so it can be woken
111        // once the lock is released.
112        shared.buffer.push_back(item);
113        let waker = shared.receiver_waker.take();
114        drop(shared);
115
116        // Drop the old item after the lock is released.
117        drop(old_item);
118
119        // Wake a receiver parked on an empty buffer.
120        if let Some(w) = waker {
121            w.wake();
122        }
123
124        true
125    }
126}
127
128impl<T> Clone for Sender<T> {
129    fn clone(&self) -> Self {
130        let mut shared = self.shared.lock();
131        shared.sender_count += 1;
132        drop(shared);
133
134        Self {
135            shared: self.shared.clone(),
136        }
137    }
138}
139
140impl<T> Drop for Sender<T> {
141    fn drop(&mut self) {
142        let mut shared = self.shared.lock();
143        shared.sender_count -= 1;
144        let waker = if shared.sender_count == 0 {
145            shared.receiver_waker.take()
146        } else {
147            None
148        };
149        drop(shared);
150
151        if let Some(w) = waker {
152            w.wake();
153        }
154    }
155}
156
157impl<T> Sink<T> for Sender<T> {
158    type Error = ChannelClosed;
159
160    fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
161        let shared = self.shared.lock();
162        if shared.receiver_dropped {
163            return Poll::Ready(Err(ChannelClosed));
164        }
165
166        Poll::Ready(Ok(()))
167    }
168
169    fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> {
170        self.send_lossy(item).then_some(()).ok_or(ChannelClosed)
171    }
172
173    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
174        // No buffering in the sender - items are sent immediately to the shared buffer
175        Poll::Ready(Ok(()))
176    }
177
178    fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
179        // Closing is handled by Drop
180        Poll::Ready(Ok(()))
181    }
182}
183
184/// The receiving half of a ring channel.
185///
186/// Implements [`Stream`] and [`FusedStream`] for receiving items. Use
187/// [`StreamExt::next`](futures::StreamExt::next) to receive items asynchronously.
188///
189/// The stream terminates (returns `None`) when all senders have been dropped
190/// and all buffered items have been consumed.
191#[derive(Debug)]
192pub struct Receiver<T> {
193    shared: Arc<Mutex<Shared<T>>>,
194}
195
196impl<T> Receiver<T> {
197    /// Receives the next item from the channel.
198    pub async fn recv(&mut self) -> Option<T> {
199        futures::future::poll_fn(|cx| Pin::new(&mut *self).poll_next(cx)).await
200    }
201
202    /// Attempts to receive an item without waiting.
203    pub fn try_recv(&mut self) -> Result<T, TryRecvError> {
204        let mut shared = self.shared.lock();
205        if let Some(item) = shared.buffer.pop_front() {
206            return Ok(item);
207        }
208        if shared.sender_count == 0 {
209            return Err(TryRecvError::Disconnected);
210        }
211        Err(TryRecvError::Empty)
212    }
213}
214
215impl<T> Stream for Receiver<T> {
216    type Item = T;
217
218    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
219        // Cloning a waker runs its callback, so clone before taking the lock.
220        let waker = cx.waker().clone();
221
222        // Deliver the oldest buffered item, or end the stream once every sender is gone.
223        let mut shared = self.shared.lock();
224        if let Some(item) = shared.buffer.pop_front() {
225            return Poll::Ready(Some(item));
226        }
227        if shared.sender_count == 0 {
228            return Poll::Ready(None);
229        }
230
231        // Register under the same lock that found the channel empty and open, so the next send or
232        // the last sender's drop wakes this task. The replaced waker is destroyed after unlocking.
233        let replaced = shared.receiver_waker.replace(waker);
234        drop(shared);
235        drop(replaced);
236        Poll::Pending
237    }
238}
239
240impl<T> FusedStream for Receiver<T> {
241    fn is_terminated(&self) -> bool {
242        let shared = self.shared.lock();
243        shared.sender_count == 0 && shared.buffer.is_empty()
244    }
245}
246
247impl<T> Drop for Receiver<T> {
248    fn drop(&mut self) {
249        let mut shared = self.shared.lock();
250        shared.receiver_dropped = true;
251
252        // Nothing reads the unread items or the waker once the receiver is gone, and a sender owned
253        // by either one keeps the channel open until they are released.
254        let buffer = mem::take(&mut shared.buffer);
255        let waker = shared.receiver_waker.take();
256        drop(shared);
257        drop(buffer);
258        drop(waker);
259    }
260}
261
262/// Creates a new ring channel with the specified capacity.
263///
264/// Returns a ([`Sender`], [`Receiver`]) pair. The sender can be cloned to create
265/// multiple producers.
266pub fn channel<T>(capacity: NonZeroUsize) -> (Sender<T>, Receiver<T>) {
267    let shared = Arc::new(Mutex::new(Shared {
268        buffer: VecDeque::with_capacity(capacity.get()),
269        capacity: capacity.get(),
270        receiver_waker: None,
271        sender_count: 1,
272        receiver_dropped: false,
273    }));
274
275    let sender = Sender {
276        shared: shared.clone(),
277    };
278    let receiver = Receiver { shared };
279
280    (sender, receiver)
281}
282
283#[cfg(test)]
284mod tests {
285    use super::*;
286    use crate::NZUsize;
287    use futures::{SinkExt, StreamExt, executor::block_on};
288    use std::{sync::Weak, task::Wake};
289
290    #[test]
291    fn test_basic_send_recv() {
292        block_on(async {
293            let (mut sender, mut receiver) = channel::<i32>(NZUsize!(10));
294
295            sender.send(1).await.unwrap();
296            sender.send(2).await.unwrap();
297            sender.send(3).await.unwrap();
298
299            assert_eq!(receiver.next().await, Some(1));
300            assert_eq!(receiver.next().await, Some(2));
301            assert_eq!(receiver.next().await, Some(3));
302        });
303    }
304
305    #[test]
306    fn test_overflow_drops_oldest() {
307        block_on(async {
308            let (mut sender, mut receiver) = channel::<i32>(NZUsize!(2));
309
310            sender.send(1).await.unwrap();
311            sender.send(2).await.unwrap();
312            sender.send(3).await.unwrap(); // Should drop 1
313            sender.send(4).await.unwrap(); // Should drop 2
314
315            assert_eq!(receiver.next().await, Some(3));
316            assert_eq!(receiver.next().await, Some(4));
317        });
318    }
319
320    #[test]
321    fn test_send_after_receiver_dropped() {
322        block_on(async {
323            let (mut sender, receiver) = channel::<i32>(NZUsize!(10));
324            drop(receiver);
325
326            let err = sender.send(1).await.unwrap_err();
327            assert!(matches!(err, ChannelClosed));
328        });
329    }
330
331    #[test]
332    fn test_recv_after_sender_dropped() {
333        block_on(async {
334            let (mut sender, mut receiver) = channel::<i32>(NZUsize!(10));
335
336            sender.send(1).await.unwrap();
337            sender.send(2).await.unwrap();
338            drop(sender);
339
340            assert_eq!(receiver.next().await, Some(1));
341            assert_eq!(receiver.next().await, Some(2));
342            assert_eq!(receiver.next().await, None);
343        });
344    }
345
346    #[test]
347    fn test_stream_collect() {
348        block_on(async {
349            let (mut sender, receiver) = channel::<i32>(NZUsize!(10));
350
351            sender.send(1).await.unwrap();
352            sender.send(2).await.unwrap();
353            sender.send(3).await.unwrap();
354            drop(sender);
355
356            let items: Vec<_> = receiver.collect().await;
357            assert_eq!(items, vec![1, 2, 3]);
358        });
359    }
360
361    #[test]
362    fn test_clone_sender() {
363        block_on(async {
364            let (mut sender1, mut receiver) = channel::<i32>(NZUsize!(10));
365            let mut sender2 = sender1.clone();
366
367            sender1.send(1).await.unwrap();
368            sender2.send(2).await.unwrap();
369
370            assert_eq!(receiver.next().await, Some(1));
371            assert_eq!(receiver.next().await, Some(2));
372        });
373    }
374
375    #[test]
376    fn test_sender_drop_with_clones() {
377        block_on(async {
378            let (sender1, mut receiver) = channel::<i32>(NZUsize!(10));
379            let mut sender2 = sender1.clone();
380
381            drop(sender1);
382
383            // Channel should still be open because sender2 exists
384            sender2.send(1).await.unwrap();
385            assert_eq!(receiver.next().await, Some(1));
386
387            drop(sender2);
388            // Now channel should be closed
389            assert_eq!(receiver.next().await, None);
390        });
391    }
392
393    #[test]
394    fn test_capacity_one() {
395        block_on(async {
396            let (mut sender, mut receiver) = channel::<i32>(NZUsize!(1));
397
398            sender.send(1).await.unwrap();
399            sender.send(2).await.unwrap(); // Drops 1
400
401            assert_eq!(receiver.next().await, Some(2));
402
403            sender.send(1).await.unwrap();
404            sender.send(2).await.unwrap(); // Drops 1
405            sender.send(3).await.unwrap(); // Drops 2
406
407            assert_eq!(receiver.next().await, Some(3));
408        });
409    }
410
411    #[test]
412    fn test_send_all() {
413        block_on(async {
414            let (mut sender, receiver) = channel::<i32>(NZUsize!(10));
415
416            let items = futures::stream::iter(vec![1, 2, 3]);
417            sender.send_all(&mut items.map(Ok)).await.unwrap();
418            drop(sender);
419
420            let received: Vec<_> = receiver.collect().await;
421            assert_eq!(received, vec![1, 2, 3]);
422        });
423    }
424
425    #[test]
426    fn test_fused_stream() {
427        use futures::stream::FusedStream;
428
429        block_on(async {
430            let (mut sender, mut receiver) = channel::<i32>(NZUsize!(10));
431
432            assert!(!receiver.is_terminated());
433
434            sender.send(1).await.unwrap();
435            assert!(!receiver.is_terminated());
436
437            drop(sender);
438            assert!(!receiver.is_terminated()); // Still has item in buffer
439
440            assert_eq!(receiver.next().await, Some(1));
441            assert!(receiver.is_terminated()); // Now terminated
442
443            // Calling next after termination returns None
444            assert_eq!(receiver.next().await, None);
445            assert!(receiver.is_terminated());
446        });
447    }
448
449    #[test]
450    fn test_is_closed() {
451        block_on(async {
452            let (sender, receiver) = channel::<i32>(NZUsize!(10));
453
454            assert!(!sender.is_closed());
455
456            drop(receiver);
457            assert!(sender.is_closed());
458        });
459    }
460
461    /// A value that owns a sender, as a task waiting on the receiver might. While the channel holds
462    /// a probe as a buffered item or as the receiver's waker, the probe's sender keeps the channel
463    /// open, so only dropping the receiver can release it.
464    ///
465    /// A probe dropped while the channel lock is held fails the test.
466    struct Probe(Option<Sender<Arc<Self>>>);
467
468    impl Probe {
469        fn new(sender: &Sender<Arc<Self>>) -> Arc<Self> {
470            Arc::new(Self(Some(sender.clone())))
471        }
472    }
473
474    #[expect(clippy::manual_noop_waker, reason = "a probe waker must own a sender")]
475    impl Wake for Probe {
476        fn wake(self: Arc<Self>) {}
477    }
478
479    impl Drop for Probe {
480        fn drop(&mut self) {
481            // The sender's destructor takes the channel lock. A probe that finds the lock held
482            // leaks its sender and fails, since dropping the sender would deadlock.
483            let sender = self.0.take().expect("a probe must still own its sender");
484            if sender.shared.try_lock().is_none() {
485                mem::forget(sender);
486                panic!("senders must be dropped outside the channel lock");
487            }
488        }
489    }
490
491    /// Parks `receiver` on a fresh [Probe] waker that only the channel holds, and returns a handle
492    /// that upgrades until the channel releases the waker.
493    fn register(sender: &Sender<Arc<Probe>>, receiver: &mut Receiver<Arc<Probe>>) -> Weak<Probe> {
494        let probe = Probe::new(sender);
495        let weak = Arc::downgrade(&probe);
496        let waker = Waker::from(probe);
497        assert!(
498            receiver
499                .poll_next_unpin(&mut Context::from_waker(&waker))
500                .is_pending(),
501            "an empty open channel must be pending"
502        );
503        drop(waker);
504        assert!(
505            weak.upgrade().is_some(),
506            "a pending receiver must register its waker"
507        );
508        weak
509    }
510
511    #[test]
512    fn test_receiver_drop_releases_unread_items() {
513        let (sender, receiver) = channel(NZUsize!(1));
514        let item = Probe::new(&sender);
515        let weak = Arc::downgrade(&item);
516        assert!(sender.send_lossy(item));
517
518        drop(receiver);
519        assert!(
520            weak.upgrade().is_none(),
521            "receiver drop must release unread items"
522        );
523    }
524
525    #[test]
526    fn test_receiver_drop_releases_waker() {
527        let (sender, mut receiver) = channel(NZUsize!(1));
528        let shared = Arc::downgrade(&sender.shared);
529        let waker = register(&sender, &mut receiver);
530
531        drop(receiver);
532        assert!(
533            waker.upgrade().is_none(),
534            "receiver drop must release its waker"
535        );
536
537        // With the waker's sender gone, dropping the last sender frees the channel.
538        drop(sender);
539        assert!(
540            shared.upgrade().is_none(),
541            "the channel must not outlive its handles"
542        );
543    }
544
545    #[test]
546    fn test_replaced_waker_dropped_outside_lock() {
547        let (sender, mut receiver) = channel(NZUsize!(1));
548        let first = register(&sender, &mut receiver);
549
550        // Registering a second waker destroys the first.
551        let second = register(&sender, &mut receiver);
552        assert!(
553            first.upgrade().is_none(),
554            "a replaced waker must be released"
555        );
556
557        // The send wakes the second waker, consuming it outside the lock, and buffers the item.
558        assert!(sender.send_lossy(Probe::new(&sender)));
559        assert!(
560            second.upgrade().is_none(),
561            "a send must consume the registered waker"
562        );
563        assert!(
564            receiver.try_recv().is_ok(),
565            "the channel must deliver after its waker is replaced"
566        );
567    }
568}