tracexec_core/primitives/
local_chan.rs

1//! Simple implementation of a `!Send` & `!Sync` channel.
2//!
3//! It is useful for single threaded scenarios.
4//!
5//! Specifically, in tracexec it is used to implement the event-action pattern:
6//! https://ratatui.rs/concepts/event-handling/#centralized-catching-message-passing
7
8use std::{
9  cell::RefCell,
10  collections::VecDeque,
11  rc::Rc,
12};
13
14pub fn unbounded<T>() -> (LocalUnboundedSender<T>, LocalUnboundedReceiver<T>) {
15  let inner = Rc::new(RefCell::new(VecDeque::new()));
16  (
17    LocalUnboundedSender {
18      inner: inner.clone(),
19    },
20    LocalUnboundedReceiver { inner },
21  )
22}
23
24#[derive(Debug, Clone)]
25pub struct LocalUnboundedSender<T> {
26  inner: Rc<RefCell<VecDeque<T>>>,
27}
28
29#[derive(Debug, Clone)]
30pub struct LocalUnboundedReceiver<T> {
31  inner: Rc<RefCell<VecDeque<T>>>,
32}
33
34impl<T> LocalUnboundedSender<T> {
35  pub fn send(&self, v: T) {
36    self.inner.borrow_mut().push_back(v);
37  }
38}
39impl<T> LocalUnboundedReceiver<T> {
40  pub fn receive(&self) -> Option<T> {
41    self.inner.borrow_mut().pop_front()
42  }
43}
44
45#[cfg(test)]
46mod tests {
47  use super::*;
48
49  #[test]
50  fn test_basic_send_receive() {
51    let (sender, receiver) = unbounded();
52
53    sender.send(42);
54    sender.send(100);
55
56    assert_eq!(receiver.receive(), Some(42));
57    assert_eq!(receiver.receive(), Some(100));
58    // Queue is now empty
59    assert_eq!(receiver.receive(), None);
60  }
61
62  #[test]
63  fn test_receive_empty_channel() {
64    let (_sender, receiver): (LocalUnboundedSender<i32>, _) = unbounded();
65    assert_eq!(receiver.receive(), None);
66  }
67
68  #[test]
69  fn test_multiple_senders_receive() {
70    let (sender1, receiver1) = unbounded();
71    let sender2 = sender1.clone();
72    let receiver2 = receiver1.clone();
73
74    sender1.send(1);
75    sender2.send(2);
76
77    // Order is preserved
78    assert_eq!(receiver1.receive(), Some(1));
79    assert_eq!(receiver2.receive(), Some(2));
80
81    // Channel empty now
82    assert_eq!(receiver1.receive(), None);
83    assert_eq!(receiver2.receive(), None);
84  }
85
86  #[test]
87  fn test_fifo_order_with_multiple_elements() {
88    let (sender, receiver) = unbounded();
89
90    for i in 0..10 {
91      sender.send(i);
92    }
93
94    for i in 0..10 {
95      assert_eq!(receiver.receive(), Some(i));
96    }
97
98    assert_eq!(receiver.receive(), None);
99  }
100
101  #[test]
102  fn test_clone_sender_receiver_shares_queue() {
103    let (sender, receiver) = unbounded();
104    let sender2 = sender.clone();
105    let receiver2 = receiver.clone();
106
107    sender.send(1);
108    sender2.send(2);
109
110    assert_eq!(receiver2.receive(), Some(1));
111    assert_eq!(receiver.receive(), Some(2));
112    assert_eq!(receiver2.receive(), None);
113  }
114}