pgwire_replication/
lsn.rs1use std::fmt;
10use std::str::FromStr;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct ParseLsnError(pub String);
15
16impl fmt::Display for ParseLsnError {
17 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 write!(f, "invalid LSN: {}", self.0)
19 }
20}
21
22impl std::error::Error for ParseLsnError {}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
47pub struct Lsn(pub u64);
48
49impl Lsn {
50 pub const ZERO: Lsn = Lsn(0);
52
53 pub fn parse(s: &str) -> Result<Lsn, ParseLsnError> {
59 let (hi_str, lo_str) = s
60 .split_once('/')
61 .ok_or_else(|| ParseLsnError(format!("missing '/' separator: {s}")))?;
62
63 let hi = u64::from_str_radix(hi_str, 16)
64 .map_err(|_| ParseLsnError(format!("invalid high part '{hi_str}': {s}")))?;
65
66 let lo = u64::from_str_radix(lo_str, 16)
67 .map_err(|_| ParseLsnError(format!("invalid low part '{lo_str}': {s}")))?;
68
69 Ok(Lsn((hi << 32) | lo))
70 }
71
72 #[inline]
74 pub fn to_pg_string(self) -> String {
75 self.to_string()
76 }
77
78 #[inline]
80 pub fn is_zero(self) -> bool {
81 self.0 == 0
82 }
83
84 #[inline]
86 pub fn as_u64(self) -> u64 {
87 self.0
88 }
89
90 #[inline]
92 pub fn from_u64(value: u64) -> Self {
93 Lsn(value)
94 }
95}
96
97impl fmt::Display for Lsn {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 let v: u64 = self.as_u64();
100 let hi = (v >> 32) as u32;
101 let lo = (v & 0xFFFF_FFFF) as u32;
102 write!(f, "{:X}/{:X}", hi, lo)
103 }
104}
105
106impl FromStr for Lsn {
107 type Err = ParseLsnError;
108
109 fn from_str(s: &str) -> Result<Self, Self::Err> {
110 Lsn::parse(s)
111 }
112}
113
114impl From<u64> for Lsn {
115 fn from(value: u64) -> Self {
116 Lsn(value)
117 }
118}
119
120impl From<Lsn> for u64 {
121 fn from(lsn: Lsn) -> Self {
122 lsn.0
123 }
124}