use crate::log::*;
use flume::{Receiver, Sender, unbounded};
#[derive(Clone)]
/// A struct abstracting over "server" threads which react to incoming events.
pub struct ChannelServer<T: Send, U: Send, V: HandleRequest<T, U>> {
request_rx: Receiver<(T, Sender<U>)>,
handler: V
}
pub trait HandleRequest<T: Send, U: Send> {
/// React to an incoming message.
fn handle(&mut self, msg: T) -> U;
}
#[derive(Clone)]
pub struct ChannelClient<T: Send, U: Send> {
/// For cloning when sending a request.
reply_tx: Sender<U>,
reply_rx: Receiver<U>,
request_tx: Sender<(T, Sender<U>)>
}
impl<T: Send, U: Send> ChannelClient<T, U> {
/// Make a request and return the appropriate response based on the handler's implementation.
pub fn request(&mut self, msg: T) -> U {
let msg = (msg, self.reply_tx.clone());
match self.request_tx.send(msg) {
Ok(_) => (),
Err(_) => {
let text = "A ChannelClient could not make a request!";
error!("{}", text);
panic!(text);
}
};
match self.reply_rx.recv() {
Ok(u) => u,
Err(_) => {
let text = "A ChannelClient could not receive a reply!";
error!("{}", text);
panic!(text)
},
}
}
}
/// Returns a client-server pair as a tuple, analoguously to MPSC channel creation.
pub fn client_server<T, U, V>(handler: V) -> (ChannelClient<T, U>, ChannelServer<T, U, V>)
where T: Send, U: Send, V: HandleRequest<T, U>
{
let (request_tx, request_rx) = unbounded::<(T, Sender<U>)>();
let (reply_tx, reply_rx) = unbounded::<U>();
let server = ChannelServer {
request_rx,
handler
};
let client = ChannelClient {
reply_tx,
reply_rx,
request_tx
};
(client, server)
}