use std::{
sync::{mpsc, mpsc::*},
time::Duration,
};
pub fn bichannel<Left, Right>() -> (Endpoint<Right, Left>, Endpoint<Left, Right>) {
let (tx_left, rx_left) = mpsc::channel::<Left>();
let (tx_right, rx_right) = mpsc::channel::<Right>();
let endpoint_left = Endpoint::new(tx_left, rx_right);
let endpoint_right = Endpoint::new(tx_right, rx_left);
(endpoint_left, endpoint_right)
}
pub struct Endpoint<In, Out> {
sender: Sender<Out>,
receiver: Receiver<In>,
}
impl<In, Out> Endpoint<In, Out> {
fn new(sender: Sender<Out>, receiver: Receiver<In>) -> Endpoint<In, Out> {
Endpoint { sender, receiver }
}
pub fn send(&self, t: Out) -> Result<(), SendError<Out>> {
self.sender.send(t)
}
pub fn try_recv(&self) -> Result<In, TryRecvError> {
self.receiver.try_recv()
}
pub fn recv(&self) -> Result<In, RecvError> {
self.receiver.recv()
}
pub fn recv_timeout(&self, timeout: Duration) -> Result<In, RecvTimeoutError> {
self.receiver.recv_timeout(timeout)
}
pub fn iter(&self) -> Iter<'_, In> {
self.receiver.iter()
}
pub fn try_iter(&self) -> TryIter<'_, In> {
self.receiver.try_iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{sync::Arc, thread, time::Duration};
use synchronoise::CountdownEvent;
struct Ping;
struct Pong;
const ROUNDTRIPS: usize = 10;
#[test]
fn ping_pong() {
let _ = env_logger::try_init();
let latch = Arc::new(CountdownEvent::new(2));
let latch_left = latch.clone();
let latch_right = latch.clone();
let (left, right) = bichannel::<Ping, Pong>();
thread::spawn(move || {
for _ in 0..ROUNDTRIPS {
left.send(Ping).expect("should send ping");
left.recv().expect("should get pong");
}
let _ = latch_left.decrement();
});
thread::spawn(move || {
for _ in 0..ROUNDTRIPS {
right.recv().expect("should get pong");
right.send(Pong).expect("should send pong");
}
let _ = latch_right.decrement();
});
let res = latch.wait_timeout(Duration::from_secs(5));
assert_eq!(res, 0);
}
}