use std::{cell::RefCell, collections::VecDeque, rc::Rc};
type Shared<T> = Rc<RefCell<SharedInner<T>>>;
#[derive(Debug)]
struct SharedInner<T> {
buffer: VecDeque<T>,
has_receiver: bool,
}
impl<T> SharedInner<T> {
fn push(&mut self, value: T) {
if self.has_receiver {
self.buffer.push_back(value);
}
}
fn pop(&mut self) -> Option<T> {
self.buffer.pop_front()
}
fn is_empty(&self) -> bool {
self.buffer.is_empty()
}
fn peek(&self) -> Option<&T> {
self.buffer.front()
}
}
impl<T> Default for SharedInner<T> {
fn default() -> Self {
Self {
buffer: Default::default(),
has_receiver: Default::default(),
}
}
}
#[derive(Debug)]
pub struct Sender<T> {
shared: Shared<T>,
}
impl<T> Sender<T> {
pub fn send(&self, msg: T) {
self.shared.borrow_mut().push(msg);
}
}
#[derive(Debug)]
pub struct Receiver<T> {
shared: Shared<T>,
}
impl<T> Receiver<T> {
fn new(shared: Shared<T>) -> Self {
shared.borrow_mut().has_receiver = true;
Self { shared }
}
pub fn recv(&self) -> Option<T> {
self.shared.borrow_mut().pop()
}
pub fn is_empty(&self) -> bool {
self.shared.borrow().is_empty()
}
pub fn peek_apply<U, F: FnOnce(&T) -> U>(&self, func: F) -> Option<U> {
self.shared.borrow().peek().map(func)
}
}
impl<T> Drop for Receiver<T> {
fn drop(&mut self) {
self.shared.borrow_mut().has_receiver = false
}
}
pub fn unbounded<T>() -> (Sender<T>, Receiver<T>) {
let shared = Rc::new(RefCell::new(SharedInner::default()));
let sender = Sender {
shared: shared.clone(),
};
let receiver = Receiver::new(shared);
(sender, receiver)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sending_without_receiver() {
let foo = Rc::new(42);
let (tx, _) = unbounded();
tx.send(foo.clone());
assert!(Rc::try_unwrap(foo).is_ok())
}
#[test]
fn send_and_receive() {
let (tx, rx) = unbounded();
tx.send("HelloWorld");
assert_eq!(rx.recv().unwrap(), "HelloWorld")
}
#[test]
fn send_and_receive_order() {
let (tx, rx) = unbounded();
tx.send("HelloWorld");
tx.send("FooBar");
assert_eq!(rx.recv().unwrap(), "HelloWorld");
assert_eq!(rx.recv().unwrap(), "FooBar");
}
#[test]
fn is_empty_receiver() {
let (tx, rx) = unbounded();
assert!(rx.is_empty());
tx.send("Foo");
assert!(!rx.is_empty());
let _ = rx.recv();
assert!(rx.is_empty());
}
#[test]
fn peek_does_not_remove() {
let (tx, rx) = unbounded();
tx.send(42);
tx.send(13);
assert_eq!(rx.peek_apply(|x| *x).unwrap(), 42);
assert_eq!(rx.recv(), Some(42));
assert_eq!(rx.peek_apply(|x| *x).unwrap(), 13);
}
macro_rules! assert_not_impl {
($x:ty, $($t:path),+ $(,)*) => {
const _: fn() -> () = || {
struct Check<T: ?Sized>(T);
trait AmbiguousIfImpl<A> { fn some_item() { } }
impl<T: ?Sized> AmbiguousIfImpl<()> for Check<T> { }
impl<T: ?Sized $(+ $t)*> AmbiguousIfImpl<u8> for Check<T> { }
<Check::<$x> as AmbiguousIfImpl<_>>::some_item()
};
};
}
#[test]
fn is_spsc() {
assert_not_impl!(Sender<()>, Copy);
assert_not_impl!(Sender<()>, Clone);
assert_not_impl!(Receiver<()>, Copy);
assert_not_impl!(Receiver<()>, Clone);
}
}