1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
16#[repr(transparent)]
17pub struct Lsn(u64);
18
19impl Lsn {
20 pub const ZERO: Lsn = Lsn(0);
21
22 pub const fn new(value: u64) -> Self {
23 Self(value)
24 }
25
26 pub const fn raw(self) -> u64 {
27 self.0
28 }
29
30 pub const fn is_zero(self) -> bool {
31 self.0 == 0
32 }
33
34 pub fn checked_next(self) -> Option<Self> {
36 self.0.checked_add(1).map(Self)
37 }
38
39 pub fn next(self) -> Self {
46 self.checked_next().unwrap_or(self)
47 }
48}
49
50impl fmt::Display for Lsn {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 write!(f, "{}", self.0)
53 }
54}
55
56impl From<u64> for Lsn {
57 fn from(value: u64) -> Self {
58 Self(value)
59 }
60}
61
62impl From<Lsn> for u64 {
63 fn from(value: Lsn) -> Self {
64 value.0
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn next_advances_monotonically() {
74 let a = Lsn::new(7);
75 let b = a.next();
76 assert!(b > a);
77 assert_eq!(b.raw(), 8);
78 }
79
80 #[test]
81 fn zero_is_sentinel() {
82 assert!(Lsn::ZERO.is_zero());
83 assert!(!Lsn::new(1).is_zero());
84 }
85
86 #[test]
87 fn overflow_saturates() {
88 assert_eq!(Lsn::new(u64::MAX).next(), Lsn::new(u64::MAX));
89 }
90}