1use crate::{span::IdSpan, CounterSpan, IdFull, IdLp, IdLpSpan, Lamport};
2
3use super::{Counter, LoroError, PeerID, ID};
4const UNKNOWN: PeerID = 404;
5use std::{
6 fmt::{Debug, Display},
7 ops::RangeBounds,
8};
9
10impl Debug for ID {
11 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12 f.write_str(format!("{}@{}", self.counter, self.peer).as_str())
13 }
14}
15
16impl Debug for IdLp {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 f.write_str(format!("L{}@{}", self.lamport, self.peer).as_str())
19 }
20}
21
22impl Display for ID {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 f.write_str(format!("{}@{}", self.counter, self.peer).as_str())
25 }
26}
27
28impl Display for IdLp {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 f.write_str(format!("L{}@{}", self.lamport, self.peer).as_str())
31 }
32}
33
34impl TryFrom<&str> for ID {
35 type Error = LoroError;
36
37 fn try_from(value: &str) -> Result<Self, Self::Error> {
38 if value.split('@').count() != 2 {
39 return Err(LoroError::DecodeError("Invalid ID format".into()));
40 }
41
42 let mut iter = value.split('@');
43 let counter = iter
44 .next()
45 .unwrap()
46 .parse::<Counter>()
47 .map_err(|_| LoroError::DecodeError("Invalid ID format".into()))?;
48 let client_id = iter
49 .next()
50 .unwrap()
51 .parse::<u64>()
52 .map_err(|_| LoroError::DecodeError("Invalid ID format".into()))?;
53 Ok(ID {
54 peer: client_id,
55 counter,
56 })
57 }
58}
59
60impl TryFrom<&str> for IdLp {
61 type Error = LoroError;
62
63 fn try_from(value: &str) -> Result<Self, Self::Error> {
64 if value.split('@').count() != 2 || !value.starts_with('L') {
65 return Err(LoroError::DecodeError("Invalid ID format".into()));
66 }
67
68 let mut iter = value[1..].split('@');
69 let lamport = iter
70 .next()
71 .unwrap()
72 .parse::<Lamport>()
73 .map_err(|_| LoroError::DecodeError("Invalid ID format".into()))?;
74 let client_id = iter
75 .next()
76 .unwrap()
77 .parse::<u64>()
78 .map_err(|_| LoroError::DecodeError("Invalid ID format".into()))?;
79 Ok(IdLp {
80 peer: client_id,
81 lamport,
82 })
83 }
84}
85
86impl PartialOrd for ID {
87 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
88 Some(self.cmp(other))
89 }
90}
91
92impl Ord for ID {
93 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
94 match self.peer.cmp(&other.peer) {
95 core::cmp::Ordering::Equal => self.counter.cmp(&other.counter),
96 ord => ord,
97 }
98 }
99}
100
101pub const ROOT_ID: ID = ID {
102 peer: PeerID::MAX,
103 counter: i32::MAX,
104};
105
106impl From<u128> for ID {
107 fn from(id: u128) -> Self {
108 ID {
109 peer: (id >> 64) as PeerID,
110 counter: id as Counter,
111 }
112 }
113}
114
115impl ID {
116 pub const NONE_ID: ID = ID::new(u64::MAX, 0);
118
119 #[inline]
120 pub const fn new(peer: PeerID, counter: Counter) -> Self {
121 ID { peer, counter }
122 }
123
124 #[inline]
125 pub fn new_root() -> Self {
126 ROOT_ID
127 }
128
129 #[inline]
130 pub fn is_null(&self) -> bool {
131 self.peer == PeerID::MAX
132 }
133
134 #[inline]
135 pub fn to_span(&self, len: usize) -> IdSpan {
136 IdSpan {
137 peer: self.peer,
138 counter: CounterSpan::new(self.counter, self.counter + len as Counter),
139 }
140 }
141
142 #[inline]
143 pub fn unknown(counter: Counter) -> Self {
144 ID {
145 peer: UNKNOWN,
146 counter,
147 }
148 }
149
150 #[inline]
151 pub fn is_unknown(&self) -> bool {
152 self.peer == UNKNOWN
153 }
154
155 #[inline]
156 #[allow(dead_code)]
157 pub(crate) fn is_connected_id(&self, other: &Self, self_len: usize) -> bool {
158 self.peer == other.peer && self.counter + self_len as Counter == other.counter
159 }
160
161 #[inline]
162 pub fn inc(&self, inc: i32) -> Self {
163 ID {
164 peer: self.peer,
165 counter: self.counter.saturating_add(inc),
166 }
167 }
168
169 #[inline]
170 pub fn contains(&self, len: Counter, target: ID) -> bool {
171 self.peer == target.peer
172 && self.counter <= target.counter
173 && target.counter < self.counter + len
174 }
175}
176
177impl From<ID> for u128 {
178 fn from(id: ID) -> Self {
179 ((id.peer as u128) << 64) | id.counter as u128
180 }
181}
182
183impl RangeBounds<ID> for (ID, ID) {
184 fn start_bound(&self) -> std::ops::Bound<&ID> {
185 std::ops::Bound::Included(&self.0)
186 }
187
188 fn end_bound(&self) -> std::ops::Bound<&ID> {
189 std::ops::Bound::Excluded(&self.1)
190 }
191}
192
193impl IdLp {
194 pub const NONE_ID: IdLp = IdLp::new(u64::MAX, 0);
195
196 #[inline]
197 pub const fn new(peer: PeerID, lp: Lamport) -> Self {
198 Self { peer, lamport: lp }
199 }
200
201 pub fn inc(&self, offset: i32) -> IdLp {
202 IdLp {
203 peer: self.peer,
204 lamport: (self.lamport as i32 + offset) as Lamport,
205 }
206 }
207
208 pub fn is_none(&self) -> bool {
209 self.peer == PeerID::MAX
210 }
211}
212
213impl From<IdLp> for IdLpSpan {
214 fn from(value: IdLp) -> Self {
215 IdLpSpan {
216 peer: value.peer,
217 lamport: crate::LamportSpan {
218 start: value.lamport,
219 end: value.lamport + 1,
220 },
221 }
222 }
223}
224
225impl IdFull {
226 pub const NONE_ID: IdFull = IdFull {
227 peer: PeerID::MAX,
228 lamport: 0,
229 counter: 0,
230 };
231
232 pub fn new(peer: PeerID, counter: Counter, lamport: Lamport) -> Self {
233 Self {
234 peer,
235 lamport,
236 counter,
237 }
238 }
239
240 pub fn inc(&self, offset: i32) -> IdFull {
241 IdFull {
242 peer: self.peer,
243 lamport: (self.lamport as i32 + offset) as Lamport,
244 counter: self.counter + offset as Counter,
245 }
246 }
247
248 pub fn id(&self) -> ID {
249 ID {
250 peer: self.peer,
251 counter: self.counter,
252 }
253 }
254
255 pub fn idlp(&self) -> IdLp {
256 IdLp {
257 peer: self.peer,
258 lamport: self.lamport,
259 }
260 }
261}