Skip to content

Commit

Permalink
Merge pull request #36 from chris-ha458/refactor
Browse files Browse the repository at this point in the history
refactor tests and impls into distinct modules
  • Loading branch information
coriolinus committed Aug 29, 2023
2 parents 9e217dc + 5161a54 commit f3bbdd7
Show file tree
Hide file tree
Showing 16 changed files with 1,227 additions and 1,139 deletions.
12 changes: 12 additions & 0 deletions src/impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
mod add_iterable;
mod add_self;
mod create;
mod deref;
mod extend;
mod from_iterator;
mod index;
mod intersection;
mod into_iterator;
mod sub_iterable;
mod sub_self;
mod union;
55 changes: 55 additions & 0 deletions src/impls/add_iterable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use crate::Counter;

use num_traits::{One, Zero};

use std::hash::Hash;
use std::ops::{Add, AddAssign};

impl<I, T, N> Add<I> for Counter<T, N>
where
I: IntoIterator<Item = T>,
T: Hash + Eq,
N: AddAssign + Zero + One,
{
type Output = Self;
/// Consume `self` producing a `Counter` like `self` updated with the counts of
/// the elements of `I`.
///
/// ```rust
/// # use counter::Counter;
/// # use std::collections::HashMap;
/// let counter = Counter::init("abbccc".chars());
///
/// let new_counter = counter + "aeeeee".chars();
/// let expected: HashMap<char, usize> = [('a', 2), ('b', 2), ('c', 3), ('e', 5)]
/// .iter().cloned().collect();
/// assert_eq!(new_counter.into_map(), expected);
/// ```
fn add(mut self, rhs: I) -> Self::Output {
self.update(rhs);
self
}
}

impl<I, T, N> AddAssign<I> for Counter<T, N>
where
I: IntoIterator<Item = T>,
T: Hash + Eq,
N: AddAssign + Zero + One,
{
/// Directly add the counts of the elements of `I` to `self`.
///
/// ```rust
/// # use counter::Counter;
/// # use std::collections::HashMap;
/// let mut counter = Counter::init("abbccc".chars());
///
/// counter += "aeeeee".chars();
/// let expected: HashMap<char, usize> = [('a', 2), ('b', 2), ('c', 3), ('e', 5)]
/// .iter().cloned().collect();
/// assert_eq!(counter.into_map(), expected);
/// ```
fn add_assign(&mut self, rhs: I) {
self.update(rhs);
}
}
62 changes: 62 additions & 0 deletions src/impls/add_self.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::Counter;

use num_traits::Zero;

use std::hash::Hash;
use std::ops::{Add, AddAssign};

impl<T, N> Add for Counter<T, N>
where
T: Clone + Hash + Eq,
N: AddAssign + Zero,
{
type Output = Counter<T, N>;

/// Add two counters together.
///
/// `out = c + d;` -> `out[x] == c[x] + d[x]` for all `x`
///
/// ```rust
/// # use counter::Counter;
/// # use std::collections::HashMap;
/// let c = "aaab".chars().collect::<Counter<_>>();
/// let d = "abb".chars().collect::<Counter<_>>();
///
/// let e = c + d;
///
/// let expect = [('a', 4), ('b', 3)].iter().cloned().collect::<HashMap<_, _>>();
/// assert_eq!(e.into_map(), expect);
/// ```
fn add(mut self, rhs: Counter<T, N>) -> Self::Output {
self += rhs;
self
}
}

impl<T, N> AddAssign for Counter<T, N>
where
T: Hash + Eq,
N: Zero + AddAssign,
{
/// Add another counter to this counter.
///
/// `c += d;` -> `c[x] += d[x]` for all `x`
///
/// ```rust
/// # use counter::Counter;
/// # use std::collections::HashMap;
/// let mut c = "aaab".chars().collect::<Counter<_>>();
/// let d = "abb".chars().collect::<Counter<_>>();
///
/// c += d;
///
/// let expect = [('a', 4), ('b', 3)].iter().cloned().collect::<HashMap<_, _>>();
/// assert_eq!(c.into_map(), expect);
/// ```
fn add_assign(&mut self, rhs: Self) {
for (key, value) in rhs.map {
let entry = self.map.entry(key).or_insert_with(N::zero);
*entry += value;
}
}
}
33 changes: 33 additions & 0 deletions src/impls/create.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use crate::Counter;

use num_traits::Zero;

use std::collections::HashMap;
use std::hash::Hash;

impl<T, N> Counter<T, N>
where
T: Hash + Eq,
N: Zero,
{
/// Create a new, empty `Counter`
pub fn new() -> Self {
Counter {
map: HashMap::new(),
zero: N::zero(),
}
}
}

impl<T, N> Default for Counter<T, N>
where
T: Hash + Eq,
N: Default,
{
fn default() -> Self {
Self {
map: Default::default(),
zero: Default::default(),
}
}
}
26 changes: 26 additions & 0 deletions src/impls/deref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use crate::Counter;

use std::collections::HashMap;
use std::hash::Hash;
use std::ops::{Deref, DerefMut};

type CounterMap<T, N> = HashMap<T, N>;

impl<T, N> Deref for Counter<T, N>
where
T: Hash + Eq,
{
type Target = CounterMap<T, N>;
fn deref(&self) -> &CounterMap<T, N> {
&self.map
}
}

impl<T, N> DerefMut for Counter<T, N>
where
T: Hash + Eq,
{
fn deref_mut(&mut self) -> &mut CounterMap<T, N> {
&mut self.map
}
}
77 changes: 77 additions & 0 deletions src/impls/extend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use crate::Counter;

use num_traits::{One, Zero};

use std::hash::Hash;
use std::ops::AddAssign;

impl<T, N> Extend<T> for Counter<T, N>
where
T: Hash + Eq,
N: AddAssign + Zero + One,
{
/// Extend a `Counter` with an iterator of items.
///
/// ```rust
/// # use counter::Counter;
/// # use std::collections::HashMap;
/// let mut counter = "abbccc".chars().collect::<Counter<_>>();
/// counter.extend("bccddd".chars());
/// let expect = [('a', 1), ('b', 3), ('c', 5), ('d', 3)].iter().cloned().collect::<HashMap<_, _>>();
/// assert_eq!(counter.into_map(), expect);
/// ```
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
self.update(iter);
}
}

impl<T, N> Extend<(T, N)> for Counter<T, N>
where
T: Hash + Eq,
N: AddAssign + Zero,
{
/// Extend a counter with `(item, count)` tuples.
///
/// The counts of duplicate items are summed.
/// ```rust
/// # use counter::Counter;
/// # use std::collections::HashMap;
/// let mut counter = "abbccc".chars().collect::<Counter<_>>();
/// counter.extend([('a', 1), ('b', 2), ('c', 3), ('a', 4)].iter().cloned());
/// let expect = [('a', 6), ('b', 4), ('c', 6)].iter()
/// .cloned().collect::<HashMap<_, _>>();
/// assert_eq!(counter.into_map(), expect);
/// ```
fn extend<I: IntoIterator<Item = (T, N)>>(&mut self, iter: I) {
for (item, item_count) in iter {
let entry = self.map.entry(item).or_insert_with(N::zero);
*entry += item_count;
}
}
}

impl<'a, T: 'a, N: 'a> Extend<(&'a T, &'a N)> for Counter<T, N>
where
T: Hash + Eq + Clone,
N: AddAssign + Zero + Clone,
{
/// Extend a counter with `(item, count)` tuples.
///
/// You can extend a `Counter` with another `Counter`:
/// ```rust
/// # use counter::Counter;
/// # use std::collections::HashMap;
/// let mut counter = "abbccc".chars().collect::<Counter<_>>();
/// let another = "bccddd".chars().collect::<Counter<_>>();
/// counter.extend(&another);
/// let expect = [('a', 1), ('b', 3), ('c', 5), ('d', 3)].iter()
/// .cloned().collect::<HashMap<_, _>>();
/// assert_eq!(counter.into_map(), expect);
/// ```
fn extend<I: IntoIterator<Item = (&'a T, &'a N)>>(&mut self, iter: I) {
for (item, item_count) in iter {
let entry = self.map.entry(item.clone()).or_insert_with(N::zero);
*entry += item_count.clone();
}
}
}
74 changes: 74 additions & 0 deletions src/impls/from_iterator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use crate::Counter;

use num_traits::{One, Zero};

use std::hash::Hash;
use std::iter;
use std::ops::AddAssign;

impl<T, N> Counter<T, N>
where
T: Hash + Eq,
N: AddAssign + Zero + One,
{
/// Create a new `Counter` initialized with the given iterable.
pub fn init<I>(iterable: I) -> Self
where
I: IntoIterator<Item = T>,
{
let mut counter = Counter::new();
counter.update(iterable);
counter
}
}

impl<T, N> iter::FromIterator<T> for Counter<T, N>
where
T: Hash + Eq,
N: AddAssign + Zero + One,
{
/// Produce a `Counter` from an iterator of items. This is called automatically
/// by [`Iterator::collect()`].
///
/// [`Iterator::collect()`]:
/// https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.collect
///
/// ```rust
/// # use counter::Counter;
/// # use std::collections::HashMap;
/// let counter = "abbccc".chars().collect::<Counter<_>>();
/// let expect = [('a', 1), ('b', 2), ('c', 3)].iter().cloned().collect::<HashMap<_, _>>();
/// assert_eq!(counter.into_map(), expect);
/// ```
///
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Counter::<T, N>::init(iter)
}
}

impl<T, N> iter::FromIterator<(T, N)> for Counter<T, N>
where
T: Hash + Eq,
N: AddAssign + Zero,
{
/// Creates a counter from `(item, count)` tuples.
///
/// The counts of duplicate items are summed.
/// ```rust
/// # use counter::Counter;
/// # use std::collections::HashMap;
/// let counter = [('a', 1), ('b', 2), ('c', 3), ('a', 4)].iter()
/// .cloned().collect::<Counter<_>>();
/// let expect = [('a', 5), ('b', 2), ('c', 3)].iter()
/// .cloned().collect::<HashMap<_, _>>();
/// assert_eq!(counter.into_map(), expect);
/// ```
fn from_iter<I: IntoIterator<Item = (T, N)>>(iter: I) -> Self {
let mut cnt = Counter::new();
for (item, item_count) in iter {
let entry = cnt.map.entry(item).or_insert_with(N::zero);
*entry += item_count;
}
cnt
}
}
Loading

0 comments on commit f3bbdd7

Please sign in to comment.