use fluent_result::into::IntoResult;
use tap::Pipe;
use crate::TryExtendOne;
use crate::errors::UnzipError;
use crate::errors::types::Either;
#[sealed::sealed]
pub trait TryUnzip {
fn try_unzip<FromA, FromB>(self) -> UnzipResult<FromA, FromB, Self>
where
FromA: Default + TryExtendOne,
FromB: Default + TryExtendOne,
Self: Iterator<Item = (FromA::Item, FromB::Item)> + Sized;
}
pub type UnzipResult<FromA, FromB, I> = Result<
(FromA, FromB),
Either<
UnzipError<<FromA as TryExtendOne>::Error, FromA, FromB, <FromB as TryExtendOne>::Item, I>,
UnzipError<<FromB as TryExtendOne>::Error, FromB, FromA, <FromA as TryExtendOne>::Item, I>,
>,
>;
type EitherUnzipError<FromA, FromB, I> = Either<
UnzipError<<FromA as TryExtendOne>::Error, FromA, FromB, <FromB as TryExtendOne>::Item, I>,
UnzipError<<FromB as TryExtendOne>::Error, FromB, FromA, <FromA as TryExtendOne>::Item, I>,
>;
#[sealed::sealed]
impl<I: Iterator> TryUnzip for I {
fn try_unzip<FromA, FromB>(mut self) -> UnzipResult<FromA, FromB, Self>
where
FromA: Default + TryExtendOne,
FromB: Default + TryExtendOne,
Self: Iterator<Item = (FromA::Item, FromB::Item)> + Sized,
{
let mut from = (FromA::default(), FromB::default());
for (a, b) in self.by_ref() {
if let Err(error) = from.0.try_extend_one(a) {
return UnzipError::new(error, from.0, from.1, Some(b), self).pipe(Either::Left).into_err();
}
if let Err(error) = from.1.try_extend_one(b) {
return UnzipError::new(error, from.1, from.0, None::<FromA::Item>, self)
.pipe::<EitherUnzipError<FromA, FromB, Self>>(Either::Right)
.into_err();
}
}
Ok(from)
}
}