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<P> {
inner: P,
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<P> Watch<P> {
pub(crate) fn new(inner: P) -> 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) -> P {
self.inner
}
}
impl<P> Producer for Watch<P>
where
P: Producer,
{
type Item = P::Item;
type Final = P::Final;
type Error = P::Error;
async fn produce(&mut self) -> Result<Either<Self::Item, Self::Final>, Self::Error> {
match self.inner.produce().await {
Ok(Left(item)) => {
self.watcher.0.count.update(|n| {
n.checked_add(1)
.expect("producer watcher cannot count more than usize::MAX items")
});
Ok(Left(item))
}
Ok(Right(fin)) => {
self.watcher.0.status.set(Status::Finalised);
Ok(Right(fin))
}
Err(err) => {
self.watcher.0.status.set(Status::Errored);
Err(err)
}
}
}
async fn slurp(&mut self) -> Result<(), Self::Error> {
let result = self.inner.slurp().await;
if result.is_err() {
self.watcher.0.status.set(Status::Errored);
}
result
}
}
impl<P> BulkProducer for Watch<P>
where
P: BulkProducer,
{
async fn expose_items_gracefully<F, R>(
&mut self,
f: F,
) -> Result<Either<R, (F, Self::Final)>, (F, Self::Error)>
where
F: AsyncFnOnce(&[Self::Item]) -> (usize, R),
{
let mut f = Some(f);
match self
.inner
.expose_items_gracefully(async |items| {
let f = f.take().expect("constructed as a Some variant");
let (produced, result) = f(items).await;
self.watcher.0.count.update(|n| {
n.checked_add(produced)
.expect("producer watcher cannot count more than usize::MAX items")
});
(produced, result)
})
.await
{
Ok(Left(result)) => Ok(Left(result)),
Ok(Right((_, fin))) => {
self.watcher.0.status.set(Status::Finalised);
Ok(Right((
f.take().expect(
"provided closure must not be called when the final item is encountered",
),
fin,
)))
}
Err((_, err)) => {
self.watcher.0.status.set(Status::Errored);
Err((
f.take()
.expect("provided closure must not be called when an error occurs"),
err,
))
}
}
}
}