Skip to main content

epoch_reset_array/
lib.rs

1use std::{
2    fmt::{Debug, Display},
3    iter,
4    marker::PhantomData,
5    mem,
6};
7
8use num_traits::{CheckedAdd, One, Zero};
9
10pub trait EpochResetArrayIndex: TryFrom<usize> + TryInto<usize> + Display + Copy {}
11
12impl<T: TryFrom<usize> + TryInto<usize> + Display + Copy> EpochResetArrayIndex for T {}
13
14pub trait EpochResetArrayValue: Clone {}
15
16impl<T: Clone> EpochResetArrayValue for T {}
17
18pub trait EpochResetArrayCounter: Zero + One + CheckedAdd + Eq + Copy + Debug {}
19
20impl<T: Zero + One + CheckedAdd + Eq + Copy + Debug> EpochResetArrayCounter for T {}
21
22#[derive(Clone)]
23pub struct EpochResetArray<Index, Value, EpochCounter> {
24    array: Vec<EpochValue<Value, EpochCounter>>,
25    reset_value: Value,
26    epoch_counter: EpochCounter,
27    phantom_data: PhantomData<Index>,
28}
29
30#[derive(Clone)]
31struct EpochValue<Value, EpochCounter> {
32    value: Value,
33    epoch_counter: EpochCounter,
34}
35
36impl<Index: EpochResetArrayIndex, Value: EpochResetArrayValue, EpochCounter: EpochResetArrayCounter>
37    EpochResetArray<Index, Value, EpochCounter>
38{
39    pub fn new(reset_value: Value, len: Index) -> Self {
40        Self {
41            array: Vec::from_iter(
42                iter::repeat_with(|| EpochValue::new(reset_value.clone(), EpochCounter::zero()))
43                    .take(index_to_usize(len)),
44            ),
45            reset_value,
46            epoch_counter: EpochCounter::zero(),
47            phantom_data: PhantomData,
48        }
49    }
50
51    pub fn len_usize(&self) -> usize {
52        self.array.len()
53    }
54
55    pub fn len_index(&self) -> Index {
56        usize_to_index(self.array.len())
57    }
58
59    pub fn is_empty(&self) -> bool {
60        self.array.is_empty()
61    }
62
63    pub fn get(&self, index: Index) -> &Value {
64        let epoch_value = &self.array[index_to_usize(index)];
65        if epoch_value.epoch_counter == self.epoch_counter {
66            &epoch_value.value
67        } else {
68            &self.reset_value
69        }
70    }
71
72    pub fn get_mut(&mut self, index: Index) -> &mut Value {
73        let epoch_value = &mut self.array[index_to_usize(index)];
74        if epoch_value.epoch_counter != self.epoch_counter {
75            *epoch_value = EpochValue::new(self.reset_value.clone(), self.epoch_counter);
76        }
77        &mut epoch_value.value
78    }
79
80    pub fn set(&mut self, index: Index, value: Value) -> Option<Value> {
81        let epoch_value = &mut self.array[index_to_usize(index)];
82        if epoch_value.epoch_counter == self.epoch_counter {
83            Some(mem::replace(&mut epoch_value.value, value))
84        } else {
85            *epoch_value = EpochValue::new(value, self.epoch_counter);
86            None
87        }
88    }
89
90    pub fn reset(&mut self) {
91        self.epoch_counter = self
92            .epoch_counter
93            .checked_add(&EpochCounter::one())
94            .unwrap_or_else(|| {
95                // Actually reset values when counter overflows.
96                self.array.iter_mut().for_each(|epoch_value| {
97                    *epoch_value = EpochValue::new(self.reset_value.clone(), EpochCounter::zero());
98                });
99
100                EpochCounter::zero()
101            });
102    }
103}
104
105impl<Value, EpochCounter> EpochValue<Value, EpochCounter> {
106    fn new(value: Value, epoch_counter: EpochCounter) -> Self {
107        Self {
108            value,
109            epoch_counter,
110        }
111    }
112}
113
114fn index_to_usize<Index: EpochResetArrayIndex>(index: Index) -> usize {
115    index
116        .try_into()
117        .unwrap_or_else(|_| panic!("Index {index} cannot be converted to usize"))
118}
119
120fn usize_to_index<Index: EpochResetArrayIndex>(index: usize) -> Index {
121    index
122        .try_into()
123        .unwrap_or_else(|_| panic!("Usize {index} cannot be converted to index type"))
124}