use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Version {
id: Uuid,
counter: usize,
}
pub const SENTINEL_VERSION: Version = Version::sentinel();
impl Version {
#[inline]
#[must_use]
pub const fn sentinel() -> Self {
Self {
id: Uuid::from_bytes([0xFF; 16]),
counter: usize::MAX,
}
}
#[inline]
#[must_use]
pub fn new() -> Self {
Self {
id: Uuid::new_v4(),
counter: 0,
}
}
#[inline]
pub fn reset(&mut self) {
self.id = Uuid::new_v4();
self.counter = 0;
}
#[inline]
pub fn increment(&mut self) {
self.counter = self.counter.wrapping_add(1);
if self.counter == 0 {
self.id = Uuid::new_v4();
}
}
#[inline]
pub fn increment_wrap(&mut self) {
self.counter = self.counter.wrapping_add(1);
}
#[inline]
#[must_use]
pub fn alike(&self, other: &Self) -> bool {
self.id == other.id
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sentinel() {
let version = Version::sentinel();
assert_eq!(version.id.as_u128(), u128::MAX);
assert_eq!(version.counter, usize::MAX);
}
#[test]
fn new() {
let version = Version::new();
assert!(version.id.as_u128() > 0);
assert_eq!(version.counter, 0);
}
#[test]
fn reset() {
let mut version = Version::new();
version.counter = 42;
let prev_id = version.id;
version.reset();
assert_ne!(version.id, prev_id);
assert_eq!(version.counter, 0);
}
#[test]
fn increment() {
let mut version = Version::new();
let prev_id = version.id;
version.increment();
assert_eq!(version.id, prev_id);
assert_eq!(version.counter, 1);
}
#[test]
fn increment_with_wrap() {
let mut version = Version::new();
version.counter = usize::MAX;
let prev_id = version.id;
version.increment();
assert_ne!(version.id, prev_id);
assert_eq!(version.counter, 0);
}
#[test]
fn increment_wrap() {
let mut version = Version::new();
let prev_id = version.id;
version.increment_wrap();
assert_eq!(version.id, prev_id);
assert_eq!(version.counter, 1);
}
#[test]
fn increment_wrap_with_wrap() {
let mut version = Version::new();
version.counter = usize::MAX;
let prev_id = version.id;
version.increment_wrap();
assert_eq!(version.id, prev_id);
assert_eq!(version.counter, 0);
}
#[test]
fn alike_match() {
let version = Version::new();
let other = version;
assert!(other.alike(&version));
}
#[test]
fn alike_mismatch() {
let version = Version::new();
let other = Version::new();
assert!(!other.alike(&version));
}
}