fluxion_test_utils/
sequenced.rs

1// Copyright 2025 Umberto Gotti <umberto.gotti@umbertogotti.dev>
2// Licensed under the Apache License, Version 2.0
3// http://www.apache.org/licenses/LICENSE-2.0
4
5use fluxion_core::{HasTimestamp, Timestamped};
6use std::cmp::Ordering;
7use std::sync::atomic::{AtomicU64, Ordering::SeqCst};
8
9static GLOBAL_SEQUENCE: AtomicU64 = AtomicU64::new(0);
10
11/// A wrapper that adds automatic sequencing to any value for temporal ordering.
12///
13/// Uses a monotonically increasing sequence counter to establish a total ordering of events.
14/// The sequence is assigned when the value is created.
15#[derive(Debug, Clone)]
16pub struct Sequenced<T> {
17    pub value: T,
18    timestamp: u64,
19}
20
21impl<T: PartialEq> PartialEq for Sequenced<T> {
22    fn eq(&self, other: &Self) -> bool {
23        self.value == other.value && self.timestamp == other.timestamp
24    }
25}
26
27impl<T: Eq> Eq for Sequenced<T> {}
28
29impl<T> Sequenced<T> {
30    /// Creates a new timestamped value with an automatically assigned sequence number.
31    pub fn new(value: T) -> Self {
32        Self {
33            value,
34            timestamp: GLOBAL_SEQUENCE.fetch_add(1, SeqCst),
35        }
36    }
37
38    pub fn with_timestamp(value: T, timestamp: u64) -> Self {
39        Self { value, timestamp }
40    }
41
42    pub fn into_inner(self) -> T {
43        self.value
44    }
45}
46
47impl<T> From<(T, u64)> for Sequenced<T> {
48    fn from((value, timestamp): (T, u64)) -> Self {
49        Self { value, timestamp }
50    }
51}
52
53impl<T> HasTimestamp for Sequenced<T>
54where
55    T: Clone + Send + Sync + 'static,
56{
57    type Timestamp = u64;
58
59    fn timestamp(&self) -> Self::Timestamp {
60        self.timestamp
61    }
62}
63
64impl<T> Timestamped for Sequenced<T>
65where
66    T: Clone + Send + Sync + 'static,
67{
68    type Inner = T;
69
70    fn into_inner(self) -> Self::Inner {
71        Self::into_inner(self)
72    }
73
74    fn with_timestamp(value: Self::Inner, timestamp: Self::Timestamp) -> Self {
75        Self::with_timestamp(value, timestamp)
76    }
77}
78
79impl<T> PartialOrd for Sequenced<T>
80where
81    T: Eq,
82{
83    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
84        Some(self.cmp(other))
85    }
86}
87
88impl<T> Ord for Sequenced<T>
89where
90    T: Eq,
91{
92    fn cmp(&self, other: &Self) -> Ordering {
93        self.timestamp.cmp(&other.timestamp)
94    }
95}