use std::fmt;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(transparent)]
pub struct Lsn(u64);
impl Lsn {
pub const ZERO: Lsn = Lsn(0);
pub const fn new(value: u64) -> Self {
Self(value)
}
pub const fn raw(self) -> u64 {
self.0
}
pub const fn is_zero(self) -> bool {
self.0 == 0
}
pub fn checked_next(self) -> Option<Self> {
self.0.checked_add(1).map(Self)
}
pub fn next(self) -> Self {
self.checked_next().unwrap_or(self)
}
}
impl fmt::Display for Lsn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<u64> for Lsn {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<Lsn> for u64 {
fn from(value: Lsn) -> Self {
value.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn next_advances_monotonically() {
let a = Lsn::new(7);
let b = a.next();
assert!(b > a);
assert_eq!(b.raw(), 8);
}
#[test]
fn zero_is_sentinel() {
assert!(Lsn::ZERO.is_zero());
assert!(!Lsn::new(1).is_zero());
}
#[test]
fn overflow_saturates() {
assert_eq!(Lsn::new(u64::MAX).next(), Lsn::new(u64::MAX));
}
}