use std::sync::mpsc;
use std::time::Duration;
use net_lattice_core::{Error, Result};
pub struct EventReceiver<E> {
receiver: mpsc::Receiver<E>,
_subscription: Option<Box<dyn Send>>,
}
impl<E> EventReceiver<E> {
pub fn new(receiver: mpsc::Receiver<E>) -> Self {
Self {
receiver,
_subscription: None,
}
}
pub fn with_subscription<S>(receiver: mpsc::Receiver<E>, subscription: S) -> Self
where
S: Send + 'static,
{
Self {
receiver,
_subscription: Some(Box::new(subscription)),
}
}
pub fn recv(&self) -> Result<E> {
self.receiver.recv().map_err(|_| Error::Disconnected)
}
pub fn try_recv(&self) -> Result<Option<E>> {
match self.receiver.try_recv() {
Ok(event) => Ok(Some(event)),
Err(mpsc::TryRecvError::Empty) => Ok(None),
Err(mpsc::TryRecvError::Disconnected) => Err(Error::Disconnected),
}
}
pub fn recv_timeout(&self, timeout: Duration) -> Result<Option<E>> {
match self.receiver.recv_timeout(timeout) {
Ok(event) => Ok(Some(event)),
Err(mpsc::RecvTimeoutError::Timeout) => Ok(None),
Err(mpsc::RecvTimeoutError::Disconnected) => Err(Error::Disconnected),
}
}
}
impl<E> Iterator for EventReceiver<E> {
type Item = E;
fn next(&mut self) -> Option<E> {
self.recv().ok()
}
}
pub trait EventProvider {
type Event;
fn watch(&self) -> Result<EventReceiver<Self::Event>>;
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
#[test]
fn recv_returns_disconnected_once_the_sender_is_dropped() {
let (sender, receiver) = mpsc::channel::<u32>();
let receiver = EventReceiver::new(receiver);
drop(sender);
assert!(matches!(receiver.recv(), Err(Error::Disconnected)));
}
#[test]
fn try_recv_returns_none_when_empty_but_still_connected() {
let (_sender, receiver) = mpsc::channel::<u32>();
let receiver = EventReceiver::new(receiver);
assert!(matches!(receiver.try_recv(), Ok(None)));
}
#[test]
fn iterator_ends_when_the_sender_is_dropped() {
let (sender, receiver) = mpsc::channel::<u32>();
let receiver = EventReceiver::new(receiver);
thread::spawn(move || {
sender.send(1).unwrap();
sender.send(2).unwrap();
});
let received: Vec<u32> = receiver.collect();
assert_eq!(received, vec![1, 2]);
}
#[test]
fn recv_timeout_returns_none_on_timeout_without_disconnecting() {
let (sender, receiver) = mpsc::channel::<u32>();
let receiver = EventReceiver::new(receiver);
assert!(matches!(
receiver.recv_timeout(Duration::from_millis(10)),
Ok(None)
));
sender.send(7).unwrap();
assert_eq!(
receiver.recv_timeout(Duration::from_secs(1)).unwrap(),
Some(7)
);
}
}