use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::{Rc, Weak};
#[derive(Debug, PartialEq, Eq)]
pub struct LocalSendError;
impl std::fmt::Display for LocalSendError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "local queue receiver dropped")
}
}
impl std::error::Error for LocalSendError {}
struct SharedQueue<T> {
deque: RefCell<VecDeque<T>>,
}
pub struct LocalSender<T> {
inner: Weak<SharedQueue<T>>,
}
impl<T> Clone for LocalSender<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<T> LocalSender<T> {
pub fn send(&self, value: T) -> Result<(), LocalSendError> {
self.inner
.upgrade()
.ok_or(LocalSendError)?
.deque
.borrow_mut()
.push_back(value);
Ok(())
}
pub fn len(&self) -> Option<usize> {
Some(self.inner.upgrade()?.deque.borrow().len())
}
pub fn is_empty(&self) -> Option<bool> {
Some(self.inner.upgrade()?.deque.borrow().is_empty())
}
}
impl<T> std::fmt::Debug for LocalSender<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LocalSender").finish_non_exhaustive()
}
}
pub struct LocalReceiver<T> {
inner: Rc<SharedQueue<T>>,
}
impl<T> LocalReceiver<T> {
pub fn try_pop(&self) -> Option<T> {
self.inner.deque.borrow_mut().pop_front()
}
pub fn len(&self) -> usize {
self.inner.deque.borrow().len()
}
pub fn is_empty(&self) -> bool {
self.inner.deque.borrow().is_empty()
}
}
impl<T> std::fmt::Debug for LocalReceiver<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LocalReceiver").finish_non_exhaustive()
}
}
pub fn local_pair<T>() -> (LocalSender<T>, LocalReceiver<T>) {
let inner = Rc::new(SharedQueue {
deque: RefCell::new(VecDeque::new()),
});
(
LocalSender {
inner: Rc::downgrade(&inner),
},
LocalReceiver { inner },
)
}
struct BroadcasterCore<T> {
subscribers: RefCell<Vec<Weak<RefCell<VecDeque<T>>>>>,
}
pub struct LocalEventSender<T> {
core: Rc<BroadcasterCore<T>>,
}
impl<T> Clone for LocalEventSender<T> {
fn clone(&self) -> Self {
Self {
core: self.core.clone(),
}
}
}
impl<T: Clone> LocalEventSender<T> {
pub fn send(&self, value: &T) {
let mut subs = self.core.subscribers.borrow_mut();
let mut dead = Vec::new();
for (idx, weak) in subs.iter().enumerate() {
match weak.upgrade() {
Some(q) => q.borrow_mut().push_back(value.clone()),
None => dead.push(idx),
}
}
for idx in dead.into_iter().rev() {
subs.swap_remove(idx);
}
}
pub fn subscriber_count(&self) -> usize {
self.core.subscribers.borrow().len()
}
}
impl<T> std::fmt::Debug for LocalEventSender<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LocalEventSender").finish_non_exhaustive()
}
}
pub struct LocalEventReceiver<T> {
queue: Rc<RefCell<VecDeque<T>>>,
}
impl<T> LocalEventReceiver<T> {
pub fn try_pop(&self) -> Option<T> {
self.queue.borrow_mut().pop_front()
}
pub fn len(&self) -> usize {
self.queue.borrow().len()
}
pub fn is_empty(&self) -> bool {
self.queue.borrow().is_empty()
}
}
impl<T> Clone for LocalEventReceiver<T> {
fn clone(&self) -> Self {
Self {
queue: self.queue.clone(),
}
}
}
impl<T> std::fmt::Debug for LocalEventReceiver<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LocalEventReceiver").finish_non_exhaustive()
}
}
pub fn local_broadcaster<T>() -> (LocalEventSender<T>, LocalEventReceiver<T>) {
let core = Rc::new(BroadcasterCore {
subscribers: RefCell::new(Vec::new()),
});
let first = Rc::new(RefCell::new(VecDeque::new()));
core.subscribers.borrow_mut().push(Rc::downgrade(&first));
(
LocalEventSender { core },
LocalEventReceiver { queue: first },
)
}
impl<T> LocalEventSender<T> {
pub fn subscribe(&self) -> LocalEventReceiver<T> {
let queue = Rc::new(RefCell::new(VecDeque::new()));
self.core
.subscribers
.borrow_mut()
.push(Rc::downgrade(&queue));
LocalEventReceiver { queue }
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
#![allow(clippy::panic)]
use super::*;
#[test]
fn local_pair_fifo_and_shared_sender() {
let (tx, rx) = local_pair::<u64>();
tx.send(1).unwrap();
tx.send(2).unwrap();
let tx2 = tx.clone();
tx2.send(3).unwrap();
assert_eq!(rx.len(), 3);
assert_eq!(rx.try_pop(), Some(1));
assert_eq!(rx.try_pop(), Some(2));
assert_eq!(rx.try_pop(), Some(3));
assert!(rx.try_pop().is_none());
assert_eq!(rx.len(), 0);
assert_eq!(tx.is_empty(), Some(true));
}
#[test]
fn local_pair_receiver_drop_yields_send_error() {
let (tx, rx) = local_pair::<u64>();
drop(rx);
assert_eq!(tx.send(1), Err(LocalSendError));
assert_eq!(tx.len(), None);
}
#[test]
fn broadcaster_fanout_no_history_and_dead_cleanup() {
let (tx, rx1) = local_broadcaster::<u64>();
tx.send(&10);
let rx2 = tx.subscribe(); assert!(rx2.try_pop().is_none());
tx.send(&20);
assert_eq!(rx1.try_pop(), Some(10));
assert_eq!(rx1.try_pop(), Some(20));
assert_eq!(rx2.try_pop(), Some(20));
assert_eq!(tx.subscriber_count(), 2);
drop(rx1);
tx.send(&30); assert_eq!(tx.subscriber_count(), 1);
assert_eq!(rx2.try_pop(), Some(30));
}
#[test]
fn local_types_are_not_send() {
fn assert_not_send<T: 'static>() {}
assert_not_send::<LocalSender<u8>>();
assert_not_send::<LocalReceiver<u8>>();
assert_not_send::<LocalEventSender<u8>>();
assert_not_send::<LocalEventReceiver<u8>>();
}
#[test]
fn receiver_len_tracks_sender_liveness() {
let (tx, rx) = local_pair::<u64>();
tx.send(1).unwrap();
assert_eq!(rx.len(), 1);
assert_eq!(tx.len(), Some(1));
drop(rx);
assert_eq!(tx.len(), None);
assert_eq!(tx.send(2), Err(LocalSendError));
}
}