use std::cell::Cell;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct CounterCell {
counter: Cell<usize>,
}
impl CounterCell {
pub fn new() -> Self {
Self::new_with(0)
}
pub fn new_with(init: usize) -> Self {
Self {
counter: Cell::new(init),
}
}
#[inline]
pub fn get(&self) -> usize {
self.counter.get()
}
#[inline]
pub fn set(&self, new_value: usize) {
self.counter.set(new_value);
}
#[inline]
pub fn incr(&self) {
self.incr_delta(1);
}
#[inline]
pub fn incr_delta(&self, delta: usize) {
self.set(self.get() + delta);
}
pub fn clear(&self) {
self.counter.set(0);
}
pub fn take(&self) -> usize {
self.counter.take()
}
#[inline]
pub fn write_back_counter(&self) -> WritebackCounterCell<'_> {
WritebackCounterCell::new(self)
}
}
pub struct OptionalCounterCell<'a> {
counter: Option<&'a CounterCell>,
}
impl<'a> OptionalCounterCell<'a> {
#[inline]
pub fn new(counter: Option<&'a CounterCell>) -> Self {
Self { counter }
}
#[inline]
pub fn get(&self) -> usize {
self.counter.map_or(0, |i| i.get())
}
#[inline]
pub fn set(&self, new_value: usize) {
if let Some(counter) = self.counter {
counter.set(new_value);
}
}
#[inline]
pub fn incr(&self) {
self.incr_delta(1);
}
#[inline]
pub fn incr_delta(&self, delta: usize) {
self.set(self.get() + delta);
}
}
pub struct WritebackCounterCell<'a> {
cell: &'a CounterCell,
counter: usize,
}
impl Drop for WritebackCounterCell<'_> {
#[inline]
fn drop(&mut self) {
self.cell.incr_delta(self.counter);
}
}
impl<'a> WritebackCounterCell<'a> {
#[inline]
fn new(cell: &'a CounterCell) -> Self {
Self { cell, counter: 0 }
}
#[inline]
pub fn incr_delta(&mut self, delta: usize) {
self.counter += delta;
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_write_back_counter() {
let cell = CounterCell::new();
{
let mut wb_counter = cell.write_back_counter();
wb_counter.incr_delta(4);
assert_eq!(cell.get(), 0);
}
assert_eq!(cell.get(), 4);
}
}