use crate::coordinate::Region;
use crate::store::writer::Notification;
use flume::Receiver;
pub struct Subscription {
rx: Receiver<Notification>,
region: Region,
}
impl Subscription {
pub(crate) fn new(rx: Receiver<Notification>, region: Region) -> Self {
Self { rx, region }
}
pub fn recv(&self) -> Option<Notification> {
loop {
match self.rx.recv() {
Ok(notif) => {
if self.region.matches_event(
notif.coord.entity(),
notif.coord.scope(),
notif.kind,
) {
return Some(notif);
}
}
Err(_) => return None, }
}
}
pub fn receiver(&self) -> &Receiver<Notification> {
&self.rx
}
pub fn ops(self) -> SubscriptionOps {
SubscriptionOps {
sub: self,
filters: Vec::new(),
map_fn: None,
limit: None,
count: 0,
}
}
}
type NotifFilter = Box<dyn Fn(&Notification) -> bool + Send>;
type NotifMapper = Box<dyn Fn(&Notification) -> Option<Notification> + Send>;
pub struct SubscriptionOps {
sub: Subscription,
filters: Vec<NotifFilter>,
map_fn: Option<NotifMapper>,
limit: Option<usize>,
count: usize,
}
impl SubscriptionOps {
pub fn filter<F: Fn(&Notification) -> bool + Send + 'static>(mut self, f: F) -> Self {
self.filters.push(Box::new(f));
self
}
pub fn map<F: Fn(&Notification) -> Option<Notification> + Send + 'static>(
mut self,
f: F,
) -> Self {
self.map_fn = Some(Box::new(f));
self
}
pub fn take(mut self, n: usize) -> Self {
self.limit = Some(n);
self
}
pub fn recv(&mut self) -> Option<Notification> {
if let Some(limit) = self.limit {
if self.count >= limit {
return None;
}
}
loop {
let notif = self.sub.recv()?;
if self.filters.iter().all(|f| f(¬if)) {
let result = if let Some(ref map_fn) = self.map_fn {
map_fn(¬if)
} else {
Some(notif)
};
if let Some(n) = result {
self.count += 1;
return Some(n);
}
}
}
}
}