use std::cmp::Ordering;
use std::iter::Cloned;
use crate::dupe::Dupe;
pub trait IterExt {
type Item;
fn try_any<F, E>(self, any: F) -> Result<bool, E>
where
Self: Sized,
F: FnMut(Self::Item) -> Result<bool, E>;
fn try_all<F, E>(self, any: F) -> Result<bool, E>
where
Self: Sized,
F: FnMut(Self::Item) -> Result<bool, E>;
fn try_eq_by<I, F, E>(self, other: I, eq: F) -> Result<bool, E>
where
Self: Sized,
I: IntoIterator,
F: FnMut(Self::Item, I::Item) -> Result<bool, E>;
fn try_cmp_by<I, F, E>(self, other: I, cmp: F) -> Result<Ordering, E>
where
Self: Sized,
I: IntoIterator,
F: FnMut(Self::Item, I::Item) -> Result<Ordering, E>;
fn try_unzip<A, B, FromA, FromB, E>(self) -> Result<(FromA, FromB), E>
where
FromA: Default + Extend<A>,
FromB: Default + Extend<B>,
Self: Iterator<Item = Result<(A, B), E>>;
fn into_singleton(self) -> Option<Self::Item>
where
Self: Sized;
}
pub trait IterDuped: Sized {
fn duped(self) -> Cloned<Self>;
}
pub trait IterOwned: Sized {
fn owned(self) -> Owned<Self>;
}
impl<I> IterExt for I
where
I: Iterator,
{
type Item = I::Item;
fn try_any<F, E>(mut self, f: F) -> Result<bool, E>
where
Self: Sized,
F: FnMut(Self::Item) -> Result<bool, E>,
{
fn check<T, E>(
mut f: impl FnMut(T) -> Result<bool, E>,
) -> impl FnMut((), T) -> Result<(), Option<E>> {
move |(), x| match f(x) {
Ok(true) => Err(None),
Ok(false) => Ok(()),
Err(e) => Err(Some(e)),
}
}
match self.try_fold((), check(f)) {
Ok(()) => Ok(false),
Err(None) => Ok(true),
Err(Some(e)) => Err(e),
}
}
fn try_all<F, E>(mut self, f: F) -> Result<bool, E>
where
Self: Sized,
F: FnMut(Self::Item) -> Result<bool, E>,
{
fn check<T, E>(
mut f: impl FnMut(T) -> Result<bool, E>,
) -> impl FnMut((), T) -> Result<(), Option<E>> {
move |(), x| match f(x) {
Ok(true) => Ok(()),
Ok(false) => Err(None),
Err(e) => Err(Some(e)),
}
}
match self.try_fold((), check(f)) {
Ok(()) => Ok(true),
Err(None) => Ok(false),
Err(Some(e)) => Err(e),
}
}
fn try_eq_by<O, F, E>(mut self, other: O, mut eq: F) -> Result<bool, E>
where
Self: Sized,
O: IntoIterator,
F: FnMut(Self::Item, O::Item) -> Result<bool, E>,
{
let mut other = other.into_iter();
loop {
let x = match self.next() {
None => return Ok(other.next().is_none()),
Some(val) => val,
};
let y = match other.next() {
None => return Ok(false),
Some(val) => val,
};
if !eq(x, y)? {
return Ok(false);
}
}
}
fn try_cmp_by<O, F, E>(mut self, other: O, mut cmp: F) -> Result<Ordering, E>
where
Self: Sized,
O: IntoIterator,
F: FnMut(Self::Item, O::Item) -> Result<Ordering, E>,
{
let mut other = other.into_iter();
loop {
let x = match self.next() {
None => {
if other.next().is_none() {
return Ok(Ordering::Equal);
} else {
return Ok(Ordering::Less);
}
}
Some(val) => val,
};
let y = match other.next() {
None => return Ok(Ordering::Greater),
Some(val) => val,
};
match cmp(x, y)? {
Ordering::Equal => {}
non_eq => return Ok(non_eq),
}
}
}
fn try_unzip<A, B, FromA, FromB, E>(self) -> Result<(FromA, FromB), E>
where
FromA: Default + Extend<A>,
FromB: Default + Extend<B>,
Self: Iterator<Item = Result<(A, B), E>>,
{
let mut ts: FromA = Default::default();
let mut us: FromB = Default::default();
for e in self {
let (t, u) = e?;
ts.extend(Some(t));
us.extend(Some(u));
}
Ok((ts, us))
}
fn into_singleton(mut self) -> Option<Self::Item>
where
Self: Sized,
{
let ret = self.next()?;
if self.next().is_some() {
return None;
}
Some(ret)
}
}
impl<'a, I, T> IterDuped for I
where
I: Sized,
I: Iterator<Item = &'a T>,
T: 'a + Dupe,
{
fn duped(self) -> Cloned<Self> {
self.cloned()
}
}
impl<'a, I, T> IterOwned for I
where
I: Iterator<Item = &'a T> + Sized,
T: 'a + ToOwned + ?Sized,
{
fn owned(self) -> Owned<Self> {
Owned { inner: self }
}
}
pub struct Owned<I> {
inner: I,
}
impl<'a, I, T> Iterator for Owned<I>
where
I: Iterator<Item = &'a T>,
T: 'a + ToOwned + ?Sized,
{
type Item = <T as ToOwned>::Owned;
fn next(&mut self) -> Option<Self::Item> {
Some(self.inner.next()?.to_owned())
}
}