ufotofu 0.12.1

Abstractions for lazily consuming and producing sequences
Documentation
use crate::errors::ProcessWhileError;
use crate::prelude::*;

/// A wrapper for a [`producer`](Producer) which continues to produce items only while those items meet a given predicate.
///
/// Use the [`into_inner`](`ProduceWhile::into_inner`) method or [`AsRef<P>`](AsRef) impl to access the wrapped producer.
///
/// Created via the [`ProducerExt::to_produce_while`] method.
///
/// <br/>Counterpart: the [consumer::ConsumeWhile] type.
///
/// #### <br/>Note:
/// It is *technically* possible to implement [`BulkProducer`] for [`ProduceWhile`], but since the resulting producer must still evaluate the predicate for each item it might produce, this represents a kind of [`"false" bulk processor`](https://worm-blossom.org/ufotofu/#zerocopy).
pub struct ProduceWhile<P, Pred> {
    inner: P,
    predicate: Pred,
}

impl<P, Pred> ProduceWhile<P, Pred> {
    pub(crate) fn new(producer: P, predicate: Pred) -> ProduceWhile<P, Pred>
    where
        P: Producer,
        Pred: AsyncFnMut(&P::Item) -> bool,
    {
        ProduceWhile {
            inner: producer,
            predicate,
        }
    }

    /// Retrieves the wrapped [`Producer`], dropping the provided predicate.
    pub fn into_inner(self) -> P {
        self.inner
    }
}

impl<P, Pred> AsRef<P> for ProduceWhile<P, Pred> {
    fn as_ref(&self) -> &P {
        &self.inner
    }
}

impl<P, Pred> Producer for ProduceWhile<P, Pred>
where
    P: Producer,
    Pred: AsyncFnMut(&P::Item) -> bool,
{
    type Item = P::Item;

    type Final = P::Final;

    type Error = ProcessWhileError<P::Item, P::Error>;

    async fn produce(&mut self) -> Result<Either<Self::Item, Self::Final>, Self::Error> {
        match self
            .inner
            .produce()
            .await
            .map_err(ProcessWhileError::Inner)?
        {
            Right(fin) => Ok(Right(fin)),
            Left(item) => {
                if (self.predicate)(&item).await {
                    Ok(Left(item))
                } else {
                    Err(ProcessWhileError::PredicateFailed(item))
                }
            }
        }
    }

    async fn slurp(&mut self) -> Result<(), Self::Error> {
        self.inner.slurp().await.map_err(ProcessWhileError::Inner)
    }
}