ironfix_session/
sequence.rs1use ironfix_core::types::SeqNum;
12use std::sync::atomic::{AtomicU64, Ordering};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
23#[error(
24 "sequence counter exhausted: {counter} reached u64::MAX, session requires a sequence reset"
25)]
26pub struct SequenceExhausted {
27 pub counter: SequenceCounter,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum SequenceCounter {
34 Sender,
36 Target,
38}
39
40impl std::fmt::Display for SequenceCounter {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 match self {
43 Self::Sender => write!(f, "sender"),
44 Self::Target => write!(f, "target"),
45 }
46 }
47}
48
49#[derive(Debug)]
53pub struct SequenceManager {
54 next_sender_seq: AtomicU64,
56 next_target_seq: AtomicU64,
58}
59
60impl SequenceManager {
61 #[must_use]
63 pub fn new() -> Self {
64 Self {
65 next_sender_seq: AtomicU64::new(1),
66 next_target_seq: AtomicU64::new(1),
67 }
68 }
69
70 #[must_use]
76 pub fn with_initial(sender_seq: u64, target_seq: u64) -> Self {
77 Self {
78 next_sender_seq: AtomicU64::new(sender_seq),
79 next_target_seq: AtomicU64::new(target_seq),
80 }
81 }
82
83 #[inline]
85 #[must_use]
86 pub fn next_sender_seq(&self) -> SeqNum {
87 SeqNum::new(self.next_sender_seq.load(Ordering::SeqCst))
88 }
89
90 #[inline]
92 #[must_use]
93 pub fn next_target_seq(&self) -> SeqNum {
94 SeqNum::new(self.next_target_seq.load(Ordering::SeqCst))
95 }
96
97 #[inline]
106 pub fn allocate_sender_seq(&self) -> SeqNum {
107 SeqNum::new(self.next_sender_seq.fetch_add(1, Ordering::SeqCst))
108 }
109
110 #[inline]
121 pub fn try_allocate_sender_seq(&self) -> Result<SeqNum, SequenceExhausted> {
122 self.next_sender_seq
123 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |current| {
124 current.checked_add(1)
125 })
126 .map(SeqNum::new)
127 .map_err(|_| SequenceExhausted {
128 counter: SequenceCounter::Sender,
129 })
130 }
131
132 #[inline]
140 pub fn increment_target_seq(&self) {
141 self.next_target_seq.fetch_add(1, Ordering::SeqCst);
142 }
143
144 #[inline]
155 pub fn try_increment_target_seq(&self) -> Result<SeqNum, SequenceExhausted> {
156 self.next_target_seq
157 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |current| {
158 current.checked_add(1)
159 })
160 .map(|previous| SeqNum::new(previous + 1))
161 .map_err(|_| SequenceExhausted {
162 counter: SequenceCounter::Target,
163 })
164 }
165
166 #[inline]
171 pub fn set_sender_seq(&self, seq: u64) {
172 self.next_sender_seq.store(seq, Ordering::SeqCst);
173 }
174
175 #[inline]
180 pub fn set_target_seq(&self, seq: u64) {
181 self.next_target_seq.store(seq, Ordering::SeqCst);
182 }
183
184 #[inline]
186 pub fn reset(&self) {
187 self.next_sender_seq.store(1, Ordering::SeqCst);
188 self.next_target_seq.store(1, Ordering::SeqCst);
189 }
190
191 #[must_use]
201 pub fn validate_incoming(&self, received: u64) -> SequenceResult {
202 let expected = self.next_target_seq.load(Ordering::SeqCst);
203
204 if received == expected {
205 SequenceResult::Ok
206 } else if received < expected {
207 SequenceResult::TooLow { expected, received }
208 } else {
209 SequenceResult::Gap { expected, received }
210 }
211 }
212}
213
214impl Default for SequenceManager {
215 fn default() -> Self {
216 Self::new()
217 }
218}
219
220#[derive(Debug, Clone, Copy, PartialEq, Eq)]
222pub enum SequenceResult {
223 Ok,
225 TooLow {
227 expected: u64,
229 received: u64,
231 },
232 Gap {
234 expected: u64,
236 received: u64,
238 },
239}
240
241impl SequenceResult {
242 #[must_use]
244 pub const fn is_ok(&self) -> bool {
245 matches!(self, Self::Ok)
246 }
247
248 #[must_use]
250 pub const fn is_gap(&self) -> bool {
251 matches!(self, Self::Gap { .. })
252 }
253
254 #[must_use]
256 pub const fn is_too_low(&self) -> bool {
257 matches!(self, Self::TooLow { .. })
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264
265 #[test]
266 fn test_sequence_manager_new() {
267 let mgr = SequenceManager::new();
268 assert_eq!(mgr.next_sender_seq().value(), 1);
269 assert_eq!(mgr.next_target_seq().value(), 1);
270 }
271
272 #[test]
273 fn test_allocate_sender_seq() {
274 let mgr = SequenceManager::new();
275
276 let seq1 = mgr.allocate_sender_seq();
277 assert_eq!(seq1.value(), 1);
278 assert_eq!(mgr.next_sender_seq().value(), 2);
279
280 let seq2 = mgr.allocate_sender_seq();
281 assert_eq!(seq2.value(), 2);
282 assert_eq!(mgr.next_sender_seq().value(), 3);
283 }
284
285 #[test]
286 fn test_increment_target_seq() {
287 let mgr = SequenceManager::new();
288
289 mgr.increment_target_seq();
290 assert_eq!(mgr.next_target_seq().value(), 2);
291
292 mgr.increment_target_seq();
293 assert_eq!(mgr.next_target_seq().value(), 3);
294 }
295
296 #[test]
297 fn test_validate_incoming() {
298 let mgr = SequenceManager::new();
299
300 assert!(mgr.validate_incoming(1).is_ok());
301
302 mgr.set_target_seq(5);
303 assert!(mgr.validate_incoming(4).is_too_low());
304 assert!(mgr.validate_incoming(5).is_ok());
305 assert!(mgr.validate_incoming(10).is_gap());
306 }
307
308 #[test]
309 fn test_try_allocate_sender_seq() {
310 let mgr = SequenceManager::new();
311
312 assert_eq!(mgr.try_allocate_sender_seq().unwrap().value(), 1);
313 assert_eq!(mgr.try_allocate_sender_seq().unwrap().value(), 2);
314 assert_eq!(mgr.next_sender_seq().value(), 3);
315 }
316
317 #[test]
318 fn test_try_allocate_sender_seq_exhausted() {
319 let mgr = SequenceManager::with_initial(u64::MAX, 1);
320
321 let err = mgr.try_allocate_sender_seq().unwrap_err();
322 assert_eq!(err.counter, SequenceCounter::Sender);
323 assert_eq!(mgr.next_sender_seq().value(), u64::MAX);
325 assert!(mgr.try_allocate_sender_seq().is_err());
326
327 mgr.reset();
329 assert_eq!(mgr.try_allocate_sender_seq().unwrap().value(), 1);
330 }
331
332 #[test]
333 fn test_try_increment_target_seq() {
334 let mgr = SequenceManager::new();
335
336 assert_eq!(mgr.try_increment_target_seq().unwrap().value(), 2);
337 assert_eq!(mgr.try_increment_target_seq().unwrap().value(), 3);
338 assert_eq!(mgr.next_target_seq().value(), 3);
339 }
340
341 #[test]
342 fn test_try_increment_target_seq_exhausted() {
343 let mgr = SequenceManager::with_initial(1, u64::MAX);
344
345 let err = mgr.try_increment_target_seq().unwrap_err();
346 assert_eq!(err.counter, SequenceCounter::Target);
347 assert_eq!(mgr.next_target_seq().value(), u64::MAX);
348 assert!(mgr.try_increment_target_seq().is_err());
349 }
350
351 #[test]
352 fn test_reset() {
353 let mgr = SequenceManager::with_initial(100, 200);
354 assert_eq!(mgr.next_sender_seq().value(), 100);
355 assert_eq!(mgr.next_target_seq().value(), 200);
356
357 mgr.reset();
358 assert_eq!(mgr.next_sender_seq().value(), 1);
359 assert_eq!(mgr.next_target_seq().value(), 1);
360 }
361}