use crate::prelude::*;
#[derive(Debug)]
pub struct Chain<P, Q> {
chained: (P, Q),
first_exhausted: bool,
}
impl<P, Q> Chain<P, Q> {
pub(crate) fn new(first: P, second: Q) -> Self {
Self {
chained: (first, second),
first_exhausted: false,
}
}
pub fn into_inner(self) -> (P, Q) {
self.chained
}
pub fn first_exhausted(&self) -> bool {
self.first_exhausted
}
}
impl<P, Q> AsRef<(P, Q)> for Chain<P, Q> {
fn as_ref(&self) -> &(P, Q) {
&self.chained
}
}
impl<P, Q> Producer for Chain<P, Q>
where
P: Producer<Final = ()>,
Q: Producer<Item = P::Item>,
{
type Item = P::Item;
type Final = Q::Final;
type Error = Either<P::Error, Q::Error>;
async fn produce(&mut self) -> Result<Either<Self::Item, Self::Final>, Self::Error> {
if !self.first_exhausted {
match self.chained.0.produce().await.map_err(Left)? {
Left(item) => return Ok(Left(item)),
Right(_) => self.first_exhausted = true,
}
}
self.chained.1.produce().await.map_err(Right)
}
async fn slurp(&mut self) -> Result<(), Self::Error> {
if !self.first_exhausted {
self.chained.0.slurp().await.map_err(Left)?;
} else {
self.chained.1.slurp().await.map_err(Right)?
}
Ok(())
}
}
impl<P, Q> BulkProducer for Chain<P, Q>
where
P: BulkProducer<Final = ()>,
Q: BulkProducer<Item = P::Item>,
{
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),
{
if self.first_exhausted {
return self
.chained
.1
.expose_items_gracefully(f)
.await
.map_err(|(f, err)| (f, Right(err)));
}
match self.chained.0.expose_items_gracefully(f).await {
Ok(Left(yay)) => Ok(Left(yay)),
Err((f, err)) => Err((f, Left(err))),
Ok(Right((f, ()))) => {
self.first_exhausted = true;
self.chained
.1
.expose_items_gracefully(f)
.await
.map_err(|(f, err)| (f, Right(err)))
}
}
}
}