use std::collections::HashMap;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::{
io,
sync::{Arc, Mutex},
};
use mio::{event, Token, Waker};
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let (tx, rx) = crossbeam::channel::unbounded();
let waker = Arc::new(Mutex::new(HashMap::new()));
(
Sender {
waker: waker.clone(),
tx,
},
Receiver {
waker,
rx,
id: 0,
next_id: Arc::new(AtomicUsize::new(1)),
},
)
}
pub struct Receiver<T> {
waker: Arc<Mutex<HashMap<usize, Option<Waker>>>>,
rx: crossbeam::channel::Receiver<T>,
id: usize,
next_id: Arc<AtomicUsize>,
}
impl<T> Clone for Receiver<T> {
fn clone(&self) -> Self {
let next_id = self.next_id.clone();
let id = next_id.fetch_add(1, Ordering::Relaxed);
Self {
waker: self.waker.clone(),
rx: self.rx.clone(),
id,
next_id,
}
}
}
impl<T> Receiver<T> {
pub fn try_recv(&self) -> Result<T, crossbeam::channel::TryRecvError> {
self.rx.try_recv()
}
}
impl<T> event::Source for Receiver<T> {
fn register(
&mut self,
registry: &mio::Registry,
token: Token,
_: mio::Interest,
) -> io::Result<()> {
let mut waker_map = self.waker.lock().unwrap();
if let Some(waker) = waker_map.get_mut(&self.id) {
if waker.is_none() {
*waker = Some(Waker::new(registry, token)?);
}
} else {
waker_map.insert(self.id, Some(Waker::new(registry, token)?));
}
Ok(())
}
fn reregister(
&mut self,
registry: &mio::Registry,
token: Token,
_: mio::Interest,
) -> io::Result<()> {
let mut waker_map = self.waker.lock().unwrap();
if let Some(waker) = waker_map.get_mut(&self.id) {
*waker = Some(Waker::new(registry, token)?);
} else {
waker_map.insert(self.id, Some(Waker::new(registry, token)?));
}
Ok(())
}
fn deregister(&mut self, _: &mio::Registry) -> io::Result<()> {
let mut waker_map = self.waker.lock().unwrap();
if let Some(waker) = waker_map.get_mut(&self.id) {
*waker = None;
}
Ok(())
}
}
pub struct Sender<T> {
waker: Arc<Mutex<HashMap<usize, Option<Waker>>>>,
tx: crossbeam::channel::Sender<T>,
}
impl<T> Sender<T> {
pub fn send(&self, t: T) -> Result<(), crossbeam::channel::SendError<T>> {
self.tx.send(t)?;
let mut waker_map = self.waker.lock().unwrap();
for waker in waker_map.values_mut().flatten() {
let _ = waker.wake();
}
Ok(())
}
}