use crossbeam_channel::{Receiver, Sender};
#[derive(Clone)]
pub struct Chan<T> {
sender: Sender<T>,
receiver: Receiver<T>,
}
impl<T> Chan<T> {
pub fn new(cap: usize) -> Self {
let (sender, receiver) = if cap == 0 {
crossbeam_channel::bounded(0)
} else {
crossbeam_channel::bounded(cap)
};
Chan { sender, receiver }
}
pub fn Send(&self, v: T) -> crate::errors::error {
match self.sender.send(v) {
Ok(()) => crate::errors::nil,
Err(_) => crate::errors::New("send on closed channel"),
}
}
pub fn Recv(&self) -> (T, bool)
where
T: Default,
{
match self.receiver.recv() {
Ok(v) => (v, true),
Err(_) => (T::default(), false),
}
}
pub fn TryRecv(&self) -> (T, bool)
where
T: Default,
{
match self.receiver.try_recv() {
Ok(v) => (v, true),
Err(_) => (T::default(), false),
}
}
pub fn Len(&self) -> crate::types::int {
self.sender.len() as crate::types::int
}
pub fn Cap(&self) -> crate::types::int {
self.sender.capacity().unwrap_or(0) as crate::types::int
}
pub fn len(&self) -> usize {
self.sender.len()
}
}
#[macro_export]
macro_rules! chan {
($t:ty, $cap:expr) => {
$crate::chan::Chan::<$t>::new($cap)
};
($t:ty) => {
$crate::chan::Chan::<$t>::new(0)
};
}
#[cfg(test)]
mod tests {
#[test]
fn buffered_send_then_recv() {
let ch = crate::chan!(i64, 4);
ch.Send(10);
ch.Send(20);
let (v, ok) = ch.Recv();
assert!(ok);
assert_eq!(v, 10);
let (v, ok) = ch.Recv();
assert!(ok);
assert_eq!(v, 20);
}
#[test]
fn try_recv_on_empty() {
let ch = crate::chan!(i64, 1);
let (_, ok) = ch.TryRecv();
assert!(!ok);
ch.Send(99);
let (v, ok) = ch.TryRecv();
assert!(ok);
assert_eq!(v, 99);
}
#[test]
fn cross_thread_buffered() {
let ch = crate::chan!(i64, 8);
let producer = ch.clone();
let handle = std::thread::spawn(move || {
for i in 0..5 {
producer.Send(i);
}
});
let mut sum = 0i64;
for _ in 0..5 {
let (v, _) = ch.Recv();
sum += v;
}
handle.join().unwrap();
assert_eq!(sum, 0 + 1 + 2 + 3 + 4);
}
#[test]
fn unbuffered_rendezvous() {
let ch = crate::chan!(i64);
let producer = ch.clone();
let handle = std::thread::spawn(move || {
producer.Send(42);
});
let (v, ok) = ch.Recv();
handle.join().unwrap();
assert!(ok);
assert_eq!(v, 42);
}
}