crabchess 0.1.15

A simple Chess API
Documentation
//! Counter for hashable items.

use fxhash::FxHashMap;
use std::{hash::Hash, iter::repeat};

/// A simple counter for hashable items, based on a `HashMap`.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Counter<T: Hash + Eq> {
    map: FxHashMap<T, isize>,
    max: isize,
}

impl<T: Hash + Eq> Counter<T> {
    /// Create an empty `Counter`.
    pub fn new() -> Self {
        Self::default()
    }

    /// Get the maximum value in the counter.
    pub const fn max(&self) -> isize {
        self.max
    }

    /// Increment a value's count.
    pub fn increment(&mut self, value: T) -> isize {
        *self
            .map
            .entry(value)
            .and_modify(|count| {
                *count += 1;
                if *count > self.max {
                    self.max = *count;
                }
            })
            .or_insert(1)
    }

    /// Decrement a value's count.
    pub fn decrement(&mut self, value: T) -> isize {
        *self
            .map
            .entry(value)
            .and_modify(|count| {
                if *count == self.max {
                    self.max -= 1;
                }
                *count -= 1;
            })
            .or_insert(-1)
    }
}

impl<T: Eq + Hash> Default for Counter<T> {
    fn default() -> Self {
        Self {
            map: FxHashMap::default(),
            max: 0,
        }
    }
}

impl<T: Hash + Eq> FromIterator<T> for Counter<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        let mut counter = Self::new();

        iter.into_iter().for_each(|v| {
            counter.increment(v);
        });

        counter
    }
}

impl<T: Clone + Eq + Hash> From<Counter<T>> for Vec<T> {
    fn from(value: Counter<T>) -> Self {
        value
            .map
            .into_iter()
            .flat_map(|(v, c)| repeat(v).take(c.try_into().unwrap_or(0)))
            .collect()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_counter() {
        let items = [3, 5, 9, 11, 14, 9, 9, 11];
        let mut counter = Counter::new();

        for item in items {
            counter.increment(item);
        }

        assert_eq!(counter.max(), 3);
    }
}