use alloc::boxed::Box;
pub type BoxIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
pub type Results<'a, T, E> = BoxIter<'a, Result<T, E>>;
pub fn box_once<'a, T: 'a>(x: T) -> BoxIter<'a, T> {
Box::new(core::iter::once(x))
}
pub fn then<'a, T, U: 'a, E: 'a>(
x: Result<T, E>,
f: impl FnOnce(T) -> Results<'a, U, E>,
) -> Results<'a, U, E> {
x.map_or_else(|e| box_once(Err(e)), f)
}
fn next_if_one<T>(iter: &mut impl Iterator<Item = T>) -> Option<T> {
if iter.size_hint().1 == Some(1) {
let ly = iter.next()?;
debug_assert!(iter.next().is_none());
return Some(ly);
}
None
}
pub fn map_with<'a, T: Clone + 'a, U: 'a, V: 'a>(
mut l: impl Iterator<Item = U> + 'a,
x: T,
r: impl Fn(U, T) -> V + 'a,
) -> BoxIter<'a, V> {
match next_if_one(&mut l) {
Some(ly) => box_once(r(ly, x)),
None => Box::new(l.map(move |ly| r(ly, x.clone()))),
}
}
pub fn flat_map_with<'a, T: Clone + 'a, U: 'a, V: 'a>(
mut l: impl Iterator<Item = U> + 'a,
x: T,
r: impl Fn(U, T) -> BoxIter<'a, V> + 'a,
) -> BoxIter<'a, V> {
match next_if_one(&mut l) {
Some(ly) => Box::new(r(ly, x)),
None => Box::new(l.flat_map(move |ly| r(ly, x.clone()))),
}
}
pub fn flat_map_then<'a, T: 'a, U: 'a, E: 'a>(
mut l: impl Iterator<Item = Result<T, E>> + 'a,
r: impl Fn(T) -> Results<'a, U, E> + 'a,
) -> Results<'a, U, E> {
match next_if_one(&mut l) {
Some(ly) => then(ly, r),
None => Box::new(l.flat_map(move |y| then(y, |y| r(y)))),
}
}
pub fn flat_map_then_with<'a, T: Clone + 'a, U: 'a, V: 'a, E: 'a>(
l: impl Iterator<Item = Result<U, E>> + 'a,
x: T,
r: impl Fn(U, T) -> Results<'a, V, E> + 'a,
) -> Results<'a, V, E> {
flat_map_with(l, x, move |y, x| then(y, |y| r(y, x)))
}