use std::fmt;
use std::sync::mpsc;
#[derive(Debug)]
pub enum EventSenderError<Category, EventSubset> {
EventSubset(mpsc::SendError<EventSubset>),
Category(mpsc::SendError<Category>),
}
#[derive(Debug)]
pub struct EventSender<Category, EventSubset> {
event_tx: mpsc::Sender<EventSubset>,
event_category: Category,
event_category_tx: mpsc::Sender<Category>,
}
impl<Category: fmt::Debug + Clone, EventSubset: fmt::Debug> EventSender<Category, EventSubset> {
pub fn new(
event_tx: mpsc::Sender<EventSubset>,
event_category: Category,
event_category_tx: mpsc::Sender<Category>,
) -> EventSender<Category, EventSubset> {
EventSender {
event_tx: event_tx,
event_category: event_category,
event_category_tx: event_category_tx,
}
}
pub fn send(&self, event: EventSubset) -> Result<(), EventSenderError<Category, EventSubset>> {
if let Err(error) = self.event_tx.send(event) {
return Err(EventSenderError::EventSubset(error));
}
if let Err(error) = self.event_category_tx.send(self.event_category.clone()) {
return Err(EventSenderError::Category(error));
}
Ok(())
}
}
impl<Category: fmt::Debug + Clone, EventSubset: fmt::Debug> Clone
for EventSender<Category, EventSubset> {
fn clone(&self) -> EventSender<Category, EventSubset> {
EventSender {
event_tx: self.event_tx.clone(),
event_category: self.event_category.clone(),
event_category_tx: self.event_category_tx.clone(),
}
}
}
#[derive(Clone, Debug)]
pub enum MaidSafeEventCategory {
Crust,
Routing,
}
pub type MaidSafeObserver<EventSubset> = EventSender<MaidSafeEventCategory, EventSubset>;
#[cfg(test)]
mod tests {
use super::*;
use std::sync::mpsc;
#[test]
fn marshall_multiple_events() {
type UiEventSender = EventSender<EventCategory, UiEvent>;
type NetworkEventSender = EventSender<EventCategory, NetworkEvent>;
const TOKEN: u32 = 9876;
const DIR_NAME: &str = "NewDirectory";
#[derive(Clone, Debug)]
enum EventCategory {
Network,
UserInterface,
}
#[derive(Debug)]
enum NetworkEvent {
Connected(u32),
Disconnected,
}
#[derive(Debug)]
enum UiEvent {
CreateDirectory(String),
Terminate,
}
let (ui_event_tx, ui_event_rx) = mpsc::channel();
let (category_tx, category_rx) = mpsc::channel();
let (network_event_tx, network_event_rx) = mpsc::channel();
let ui_event_sender = UiEventSender::new(
ui_event_tx,
EventCategory::UserInterface,
category_tx.clone(),
);
let nw_event_sender =
NetworkEventSender::new(network_event_tx, EventCategory::Network, category_tx);
let _joiner = ::thread::named(
"EventListenerThread",
move || for it in category_rx.iter() {
match it {
EventCategory::Network => {
if let Ok(network_event) = network_event_rx.try_recv() {
if let NetworkEvent::Connected(token) = network_event {
assert_eq!(token, TOKEN)
} else {
panic!("Shouldn't have received this event: {:?}", network_event)
}
}
}
EventCategory::UserInterface => {
if let Ok(ui_event) = ui_event_rx.try_recv() {
match ui_event {
UiEvent::CreateDirectory(name) => assert_eq!(name, DIR_NAME),
UiEvent::Terminate => break,
}
}
}
}
},
);
assert!(nw_event_sender.send(NetworkEvent::Connected(TOKEN)).is_ok());
assert!(
ui_event_sender
.send(UiEvent::CreateDirectory(DIR_NAME.to_string()))
.is_ok()
);
assert!(ui_event_sender.send(UiEvent::Terminate).is_ok());
::std::thread::sleep(::std::time::Duration::from_millis(500));
assert!(ui_event_sender.send(UiEvent::Terminate).is_err());
assert!(nw_event_sender.send(NetworkEvent::Disconnected).is_err());
let result = ui_event_sender
.send(UiEvent::CreateDirectory(DIR_NAME.to_owned()))
.err();
if let EventSenderError::EventSubset(send_err) = unwrap!(result) {
if let UiEvent::CreateDirectory(dir_name) = send_err.0 {
assert_eq!(dir_name, DIR_NAME)
} else {
panic!("Expected a different event !")
}
} else {
panic!("Expected a different error !")
}
}
}