graphrs 0.11.16

graphrs is a Rust package for the creation, manipulation and analysis of graphs.
Documentation
use itertools::Itertools;
use nohash::{IntSet, IsEnabled};
use std::hash::Hash;

pub struct ChunkByCount<I: Iterator> {
    #[allow(clippy::type_complexity)]
    inner: itertools::structs::ChunkBy<I::Item, I, fn(&I::Item) -> I::Item>,
}

impl<I> Iterator for ChunkByCount<I>
where
    I: Iterator,
    I::Item: PartialEq,
{
    type Item = (I::Item, usize);

    fn next(&mut self) -> Option<Self::Item> {
        self.inner
            .into_iter()
            .next()
            .map(|(key, chunk)| (key, chunk.count()))
    }
}

pub struct UniqueByNoHash<I: Iterator, V, F> {
    inner: I,
    seen: IntSet<V>,
    f: F,
}

impl<I, V, F> Iterator for UniqueByNoHash<I, V, F>
where
    I: Iterator,
    V: IsEnabled + Hash + Eq,
    F: FnMut(&I::Item) -> V,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next().filter(|x| {
            let key = (self.f)(x);
            let r = !self.seen.contains(&key);
            self.seen.insert(key);
            r
        })
    }
}

pub trait IteratorExt: Iterator {
    fn chunk_by_count(self) -> ChunkByCount<Self>
    where
        Self: Sized;
    fn unique_by_no_hash<V, F>(self, f: F) -> UniqueByNoHash<Self, V, F>
    where
        Self: Sized,
        V: IsEnabled + Hash + Eq,
        for<'a> F: FnMut(&'a Self::Item) -> V;
}

impl<I> IteratorExt for I
where
    I: Iterator,
    I::Item: Clone + PartialEq,
{
    fn chunk_by_count(self) -> ChunkByCount<Self>
    where
        Self: Sized,
    {
        ChunkByCount {
            inner: self.chunk_by(|i| i.clone()),
        }
    }
    fn unique_by_no_hash<V, F>(self, f: F) -> UniqueByNoHash<Self, V, F>
    where
        Self: Sized,
        V: IsEnabled + Hash + Eq,
        F: FnMut(&I::Item) -> V,
    {
        UniqueByNoHash::<Self, V, F> {
            inner: self,
            seen: IntSet::<V>::default(),
            f,
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use std::collections::HashMap;

    #[test]
    fn test_group_by_count_1() {
        let data = vec![1, 3, -2, -2, 1, 0, 1, 2];
        let result: HashMap<i32, usize> = data.into_iter().sorted().chunk_by_count().collect();
        assert_eq!(result.get(&-2).unwrap(), &2);
        assert_eq!(result.get(&0).unwrap(), &1);
        assert_eq!(result.get(&1).unwrap(), &3);
        assert_eq!(result.get(&2).unwrap(), &1);
    }
}