use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Duration;
use crate::error::{Error, Result};
use crate::link::Link;
use crate::types::{CatchMask, InputReport};
use super::Device;
#[derive(Clone, Debug)]
pub struct EventStream {
rx: flume::Receiver<InputReport>,
dropped: Arc<AtomicU64>,
_guard: Arc<CatchGuard>,
}
#[derive(Debug)]
struct CatchGuard {
link: Link,
id: u64,
}
impl Drop for CatchGuard {
fn drop(&mut self) {
self.link.catch_unsubscribe(self.id);
}
}
impl EventStream {
pub(crate) fn new(
rx: flume::Receiver<InputReport>,
dropped: Arc<AtomicU64>,
link: Link,
id: u64,
) -> EventStream {
EventStream {
rx,
dropped,
_guard: Arc::new(CatchGuard { link, id }),
}
}
pub fn recv(&self) -> Result<InputReport> {
self.rx.recv().map_err(|_| Error::Disconnected)
}
pub fn try_recv(&self) -> Option<InputReport> {
self.rx.try_recv().ok()
}
pub fn recv_timeout(&self, timeout: Duration) -> Option<InputReport> {
self.rx.recv_timeout(timeout).ok()
}
pub fn try_iter(&self) -> impl Iterator<Item = InputReport> + '_ {
self.rx.try_iter()
}
#[cfg(feature = "async")]
pub async fn recv_async(&self) -> Result<InputReport> {
self.rx.recv_async().await.map_err(|_| Error::Disconnected)
}
pub fn dropped(&self) -> u64 {
self.dropped.load(Ordering::Relaxed)
}
}
impl Device {
pub fn catch_events(&self, mask: CatchMask) -> Result<EventStream> {
let (id, rx, dropped) = self.link.catch_subscribe(mask)?;
Ok(EventStream::new(rx, dropped, self.link.clone(), id))
}
}