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 {
43 self.checked_next()
44 .expect("Lsn overflowed; the WAL has been continuously running for ~580 My")
45 }
46}
47
48impl fmt::Display for Lsn {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(f, "{}", self.0)
51 }
52}
53
54impl From<u64> for Lsn {
55 fn from(value: u64) -> Self {
56 Self(value)
57 }
58}
59
60impl From<Lsn> for u64 {
61 fn from(value: Lsn) -> Self {
62 value.0
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn next_advances_monotonically() {
72 let a = Lsn::new(7);
73 let b = a.next();
74 assert!(b > a);
75 assert_eq!(b.raw(), 8);
76 }
77
78 #[test]
79 fn zero_is_sentinel() {
80 assert!(Lsn::ZERO.is_zero());
81 assert!(!Lsn::new(1).is_zero());
82 }
83
84 #[test]
85 #[should_panic(expected = "Lsn overflowed")]
86 fn overflow_panics() {
87 let _ = Lsn::new(u64::MAX).next();
88 }
89}