use std::fmt; use std::iter::FusedIterator; use crate::size_hint; #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub struct CoalesceBy where I: Iterator, C: CountItem, { iter: I, /// `last` is `None` while no item have been taken out of `iter` (at definition). /// Then `last` will be `Some(Some(item))` until `iter` is exhausted, /// in which case `last` will be `Some(None)`. last: Option>, f: F, } impl Clone for CoalesceBy where I: Clone + Iterator, F: Clone, C: CountItem, C::CItem: Clone, { clone_fields!(last, iter, f); } impl fmt::Debug for CoalesceBy where I: Iterator + fmt::Debug, C: CountItem, C::CItem: fmt::Debug, { debug_fmt_fields!(CoalesceBy, iter, last); } pub trait CoalescePredicate { fn coalesce_pair(&mut self, t: T, item: Item) -> Result; } impl Iterator for CoalesceBy where I: Iterator, F: CoalescePredicate, C: CountItem, { type Item = C::CItem; fn next(&mut self) -> Option { let Self { iter, last, f } = self; // this fuses the iterator let init = match last { Some(elt) => elt.take(), None => { *last = Some(None); iter.next().map(C::new) } }?; Some( iter.try_fold(init, |accum, next| match f.coalesce_pair(accum, next) { Ok(joined) => Ok(joined), Err((last_, next_)) => { *last = Some(Some(next_)); Err(last_) } }) .unwrap_or_else(|x| x), ) } fn size_hint(&self) -> (usize, Option) { let (low, hi) = size_hint::add_scalar( self.iter.size_hint(), matches!(self.last, Some(Some(_))) as usize, ); ((low > 0) as usize, hi) } fn fold(self, acc: Acc, mut fn_acc: FnAcc) -> Acc where FnAcc: FnMut(Acc, Self::Item) -> Acc, { let Self { mut iter, last, mut f, } = self; if let Some(last) = last.unwrap_or_else(|| iter.next().map(C::new)) { let (last, acc) = iter.fold((last, acc), |(last, acc), elt| { match f.coalesce_pair(last, elt) { Ok(joined) => (joined, acc), Err((last_, next_)) => (next_, fn_acc(acc, last_)), } }); fn_acc(acc, last) } else { acc } } } impl FusedIterator for CoalesceBy where I: Iterator, F: CoalescePredicate, C: CountItem, { } pub struct NoCount; pub struct WithCount; pub trait CountItem { type CItem; fn new(t: T) -> Self::CItem; } impl CountItem for NoCount { type CItem = T; #[inline(always)] fn new(t: T) -> T { t } } impl CountItem for WithCount { type CItem = (usize, T); #[inline(always)] fn new(t: T) -> (usize, T) { (1, t) } } /// An iterator adaptor that may join together adjacent elements. /// /// See [`.coalesce()`](crate::Itertools::coalesce) for more information. pub type Coalesce = CoalesceBy; impl CoalescePredicate for F where F: FnMut(T, Item) -> Result, { fn coalesce_pair(&mut self, t: T, item: Item) -> Result { self(t, item) } } /// Create a new `Coalesce`. pub fn coalesce(iter: I, f: F) -> Coalesce where I: Iterator, { Coalesce { last: None, iter, f, } } /// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function. /// /// See [`.dedup_by()`](crate::Itertools::dedup_by) or [`.dedup()`](crate::Itertools::dedup) for more information. pub type DedupBy = CoalesceBy, NoCount>; #[derive(Clone)] pub struct DedupPred2CoalescePred(DP); impl fmt::Debug for DedupPred2CoalescePred { debug_fmt_fields!(DedupPred2CoalescePred,); } pub trait DedupPredicate { // TODO replace by Fn(&T, &T)->bool once Rust supports it fn dedup_pair(&mut self, a: &T, b: &T) -> bool; } impl CoalescePredicate for DedupPred2CoalescePred where DP: DedupPredicate, { fn coalesce_pair(&mut self, t: T, item: T) -> Result { if self.0.dedup_pair(&t, &item) { Ok(t) } else { Err((t, item)) } } } #[derive(Clone, Debug)] pub struct DedupEq; impl DedupPredicate for DedupEq { fn dedup_pair(&mut self, a: &T, b: &T) -> bool { a == b } } impl bool> DedupPredicate for F { fn dedup_pair(&mut self, a: &T, b: &T) -> bool { self(a, b) } } /// Create a new `DedupBy`. pub fn dedup_by(iter: I, dedup_pred: Pred) -> DedupBy where I: Iterator, { DedupBy { last: None, iter, f: DedupPred2CoalescePred(dedup_pred), } } /// An iterator adaptor that removes repeated duplicates. /// /// See [`.dedup()`](crate::Itertools::dedup) for more information. pub type Dedup = DedupBy; /// Create a new `Dedup`. pub fn dedup(iter: I) -> Dedup where I: Iterator, { dedup_by(iter, DedupEq) } /// An iterator adaptor that removes repeated duplicates, while keeping a count of how many /// repeated elements were present. This will determine equality using a comparison function. /// /// See [`.dedup_by_with_count()`](crate::Itertools::dedup_by_with_count) or /// [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information. pub type DedupByWithCount = CoalesceBy, WithCount>; #[derive(Clone, Debug)] pub struct DedupPredWithCount2CoalescePred(DP); impl CoalescePredicate for DedupPredWithCount2CoalescePred where DP: DedupPredicate, { fn coalesce_pair( &mut self, (c, t): (usize, T), item: T, ) -> Result<(usize, T), ((usize, T), (usize, T))> { if self.0.dedup_pair(&t, &item) { Ok((c + 1, t)) } else { Err(((c, t), (1, item))) } } } /// An iterator adaptor that removes repeated duplicates, while keeping a count of how many /// repeated elements were present. /// /// See [`.dedup_with_count()`](crate::Itertools::dedup_with_count) for more information. pub type DedupWithCount = DedupByWithCount; /// Create a new `DedupByWithCount`. pub fn dedup_by_with_count(iter: I, dedup_pred: Pred) -> DedupByWithCount where I: Iterator, { DedupByWithCount { last: None, iter, f: DedupPredWithCount2CoalescePred(dedup_pred), } } /// Create a new `DedupWithCount`. pub fn dedup_with_count(iter: I) -> DedupWithCount where I: Iterator, { dedup_by_with_count(iter, DedupEq) }