use crate::prelude::*;
use alloc::rc::Rc;
use core::cell::Cell;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Status {
Processing,
Finalised,
Errored,
}
struct WatcherInner {
count: Cell<usize>,
status: Cell<Status>,
}
#[derive(Clone)]
pub struct Watcher(Rc<WatcherInner>);
pub struct Watch<C> {
inner: C,
watcher: Watcher,
}
impl Watcher {
fn new() -> Self {
Self(Rc::new(WatcherInner {
count: Cell::new(0),
status: Cell::new(Status::Processing),
}))
}
pub fn count(&self) -> usize {
self.0.count.get()
}
pub fn status(&self) -> Status {
self.0.status.get()
}
}
impl<C> Watch<C> {
pub(crate) fn new(inner: C) -> Self {
let watcher = Watcher::new();
Watch { inner, watcher }
}
pub fn watcher(&self) -> Watcher {
self.watcher.clone()
}
pub fn count(&self) -> usize {
self.watcher.count()
}
pub fn into_inner(self) -> C {
self.inner
}
}
impl<C> Consumer for Watch<C>
where
C: Consumer,
{
type Item = C::Item;
type Final = C::Final;
type Error = C::Error;
async fn consume(&mut self, val: Either<Self::Item, Self::Final>) -> Result<(), Self::Error> {
let finalised = val.is_right();
match self.inner.consume(val).await {
Ok(()) => {
if finalised {
self.watcher.0.status.set(Status::Finalised);
} else {
self.watcher.0.count.update(|n| {
n.checked_add(1)
.expect("consumer watcher cannot count more than usize::MAX items")
});
}
Ok(())
}
Err(err) => {
self.watcher.0.status.set(Status::Errored);
Err(err)
}
}
}
async fn flush(&mut self) -> Result<(), Self::Error> {
let result = self.inner.flush().await;
if result.is_err() {
self.watcher.0.status.set(Status::Errored)
}
result
}
}
impl<C> BulkConsumer for Watch<C>
where
C: BulkConsumer,
{
async fn expose_slots_gracefully<F, R>(&mut self, f: F) -> Result<R, (F, Self::Error)>
where
F: AsyncFnOnce(&mut [Self::Item]) -> (usize, R),
{
let mut f = Some(f);
match self
.inner
.expose_slots_gracefully(async |items| {
let f = f.take().expect("constructed as a Some variant");
let (consumed, result) = f(items).await;
self.watcher.0.count.update(|n| {
n.checked_add(consumed)
.expect("consumer watcher cannot count more than usize::MAX items")
});
(consumed, result)
})
.await
{
Ok(result) => Ok(result),
Err((_, err)) => {
self.watcher.0.status.set(Status::Errored);
Err((
f.take()
.expect("provided closure must not be called when an error occurs"),
err,
))
}
}
}
}