use std::marker::PhantomData;
#[derive(Debug, Clone)]
pub struct Coverage<T: ?Sized> {
state: Vec<u8>,
phantom: PhantomData<T>,
}
impl<T: Position> Coverage<T> {
pub fn new(quantity: usize) -> Self {
Self {
state: vec![0; quantity],
phantom: PhantomData,
}
}
pub fn cover(&mut self, element: T) {
self.state[element.position()] += 1;
}
pub fn uncover(&mut self, element: T) {
self.state[element.position()] -= 1;
}
pub fn count(&self, element: T) -> usize {
self.state[element.position()] as usize
}
pub fn is_covered(&self, element: T) -> bool {
self.state[element.position()] > 0
}
pub fn merge(&mut self, other: &Self) {
self.state
.iter_mut()
.enumerate()
.for_each(|(position, cover)| *cover += other.state[position] as u8);
}
pub fn reset(&mut self) {
self.state.fill(0);
}
}
pub trait Position {
fn position(&self) -> usize;
}
macro_rules! impl_position_for_numbers {
($($number:ident),+) => ($(
impl Position for $number {
fn position(&self) -> usize {
*self as usize
}
}
)*)
}
impl_position_for_numbers!(i32, isize, u32, usize, f64);
#[cfg(test)]
mod tests {
use super::Coverage;
#[test]
fn test_coverage() {
let quantity = 10;
let mut coverage = Coverage::new(quantity);
coverage.cover(5);
assert_eq!(coverage.count(5), 1);
assert_eq!(coverage.count(2), 0);
coverage.cover(5);
assert_eq!(coverage.count(5), 2);
}
#[test]
#[should_panic]
fn test_invalid_position() {
let mut coverage = Coverage::new(5);
coverage.cover(20);
coverage.count(50);
}
}