use std::num::NonZeroU32;
#[derive(Debug, Clone)]
pub struct SymbolCounter {
next_id: NonZeroU32,
}
impl SymbolCounter {
#[must_use]
pub fn new() -> Self {
Self {
next_id: NonZeroU32::new(1).expect("1 is non-zero"),
}
}
pub fn next_id(&mut self) -> super::SymbolId {
let current = self.next_id;
self.next_id = NonZeroU32::new(
current
.get()
.checked_add(1)
.expect("Symbol counter overflow - file has more than 4 billion symbols"),
)
.expect("Incremented value is non-zero");
super::SymbolId(current.get())
}
#[must_use]
pub fn current_count(&self) -> u32 {
self.next_id.get() - 1
}
pub fn reset(&mut self) {
self.next_id = NonZeroU32::new(1).expect("1 is non-zero");
}
pub fn from_value(start_from: u32) -> Self {
Self {
next_id: NonZeroU32::new(start_from).expect("Counter value must be non-zero"),
}
}
}
impl Default for SymbolCounter {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_symbol_counter_starts_at_one() {
let mut counter = SymbolCounter::new();
let first_id = counter.next_id();
assert_eq!(first_id.0, 1);
}
#[test]
fn test_symbol_counter_increments() {
let mut counter = SymbolCounter::new();
let id1 = counter.next_id();
let id2 = counter.next_id();
let id3 = counter.next_id();
assert_eq!(id1.0, 1);
assert_eq!(id2.0, 2);
assert_eq!(id3.0, 3);
}
#[test]
fn test_current_count() {
let mut counter = SymbolCounter::new();
assert_eq!(counter.current_count(), 0);
counter.next_id();
assert_eq!(counter.current_count(), 1);
counter.next_id();
counter.next_id();
assert_eq!(counter.current_count(), 3);
}
#[test]
fn test_reset() {
let mut counter = SymbolCounter::new();
counter.next_id();
counter.next_id();
counter.next_id();
assert_eq!(counter.current_count(), 3);
counter.reset();
assert_eq!(counter.current_count(), 0);
let first_after_reset = counter.next_id();
assert_eq!(first_after_reset.0, 1);
}
#[test]
fn test_default_impl() {
let counter = SymbolCounter::default();
assert_eq!(counter.current_count(), 0);
}
}