kanidmd_lib/repl/
cid.rs
1use std::fmt;
2use std::time::Duration;
3use time::OffsetDateTime;
4
5use crate::be::dbvalue::DbCidV1;
6use crate::prelude::*;
7use serde::{Deserialize, Serialize};
8
9#[derive(Serialize, Deserialize, PartialEq, Clone, Eq, PartialOrd, Ord, Hash)]
10pub struct Cid {
11 pub ts: Duration,
13 pub s_uuid: Uuid,
14}
15
16impl From<DbCidV1> for Cid {
17 fn from(
18 DbCidV1 {
19 server_id,
20 timestamp,
21 }: DbCidV1,
22 ) -> Self {
23 Cid {
24 ts: timestamp,
25 s_uuid: server_id,
26 }
27 }
28}
29
30impl fmt::Debug for Cid {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 write!(f, "{:032}-{}", self.ts.as_nanos(), self.s_uuid)
33 }
34}
35
36impl fmt::Display for Cid {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(f, "{:032}-{}", self.ts.as_nanos(), self.s_uuid)
39 }
40}
41
42impl From<&Cid> for OffsetDateTime {
43 fn from(cid: &Cid) -> Self {
44 OffsetDateTime::UNIX_EPOCH + cid.ts
45 }
46}
47
48impl Cid {
49 pub(crate) fn new(s_uuid: Uuid, ts: Duration) -> Self {
50 Cid { s_uuid, ts }
51 }
52
53 pub fn new_lamport(s_uuid: Uuid, ts: Duration, max_ts: &Duration) -> Self {
54 let ts = if ts > *max_ts {
55 ts
56 } else {
57 *max_ts + Duration::from_nanos(1)
58 };
59 Cid { ts, s_uuid }
60 }
61
62 #[cfg(test)]
65 pub fn new_zero() -> Self {
66 Self::new_count(0)
67 }
68
69 #[cfg(test)]
72 pub fn new_count(c: u64) -> Self {
73 Cid {
74 s_uuid: uuid!("00000000-0000-0000-0000-000000000000"),
75 ts: Duration::new(c, 0),
76 }
77 }
78
79 pub fn sub_secs(&self, secs: u64) -> Result<Self, OperationError> {
80 self.ts
81 .checked_sub(Duration::from_secs(secs))
82 .map(|r| Cid {
83 s_uuid: uuid!("00000000-0000-0000-0000-000000000000"),
84 ts: r,
85 })
86 .ok_or(OperationError::InvalidReplChangeId)
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use crate::prelude::*;
93 use std::cmp::Ordering;
94 use std::time::Duration;
95
96 use crate::repl::cid::Cid;
97
98 #[test]
99 fn test_cid_ordering() {
100 let cid_a = Cid::new(
102 uuid!("00000000-0000-0000-0000-000000000001"),
103 Duration::new(5, 0),
104 );
105 let cid_b = Cid::new(
106 uuid!("00000000-0000-0000-0000-000000000001"),
107 Duration::new(15, 0),
108 );
109
110 assert_eq!(cid_a.cmp(&cid_a), Ordering::Equal);
111 assert_eq!(cid_a.cmp(&cid_b), Ordering::Less);
112 assert_eq!(cid_b.cmp(&cid_a), Ordering::Greater);
113
114 let cid_e = Cid::new(
116 uuid!("00000000-0000-0000-0000-000000000000"),
117 Duration::new(5, 0),
118 );
119 let cid_f = Cid::new(
120 uuid!("00000000-0000-0000-0000-000000000001"),
121 Duration::new(5, 0),
122 );
123
124 assert_eq!(cid_e.cmp(&cid_e), Ordering::Equal);
125 assert_eq!(cid_e.cmp(&cid_f), Ordering::Less);
126 assert_eq!(cid_f.cmp(&cid_e), Ordering::Greater);
127 }
128
129 #[test]
130 fn test_cid_lamport() {
131 let s_uuid = uuid!("00000000-0000-0000-0000-000000000001");
132
133 let ts5 = Duration::new(5, 0);
134 let ts10 = Duration::new(10, 0);
135 let ts15 = Duration::new(15, 0);
136
137 let cid_z = Cid::new_zero();
138
139 let cid_a = Cid::new_lamport(s_uuid, ts5, &ts5);
140 assert_eq!(cid_a.cmp(&cid_z), Ordering::Greater);
141 let cid_b = Cid::new_lamport(s_uuid, ts15, &ts10);
142 assert_eq!(cid_b.cmp(&cid_a), Ordering::Greater);
143 let cid_c = Cid::new_lamport(s_uuid, ts10, &ts15);
145 assert_eq!(cid_c.cmp(&cid_b), Ordering::Greater);
146 }
147}