1use std::{
4 sync::atomic::{
5 AtomicU64,
6 Ordering::{Acquire, Release, SeqCst},
7 },
8 time::SystemTime,
9};
10
11pub const EPOCH: u64 = 1637806706000;
12#[cfg(not(test))]
13const SEQUENCE_BITS: u8 = 12;
14#[cfg(test)]
15const SEQUENCE_BITS: u8 = 1;
16const TIMESTAMP_SHIFT: u8 = SEQUENCE_BITS;
17const SEQUENCE_MASK: u64 = (1 << SEQUENCE_BITS) - 1;
18
19pub type NID = u64;
20pub type SIDGEN = AtomicU64;
21pub type SID = u64;
22
23#[derive(Default)]
25pub struct Seq(SIDGEN);
26impl Seq {
29 pub fn new() -> Seq {
39 Seq(SIDGEN::new(0))
40 }
41
42 pub fn next_id(&self) -> SID {
53 self.0.fetch_add(1, SeqCst)
54 }
55
56 pub fn reset(&self) {
67 self.0.store(0, Release);
68 }
69}
70impl From<SID> for Seq {
71 fn from(value: SID) -> Self {
72 Seq(SIDGEN::new(value))
73 }
74}
75#[derive(Default)]
77pub struct TimestampSeq {
78 sequence: AtomicU64,
79 last_cycle_timestamp: AtomicU64,
80}
81fn get_timestamp() -> u64 {
84 SystemTime::now()
85 .duration_since(SystemTime::UNIX_EPOCH)
86 .expect("Clock moved backwards!")
87 .as_millis() as u64
88}
89impl TimestampSeq {
90 pub fn new() -> TimestampSeq {
92 TimestampSeq::default()
93 }
94
95 fn wait_next_millis(&self) {
96 let last_timestamp = self.last_cycle_timestamp.load(Acquire);
97 while get_timestamp() <= last_timestamp {}
98 }
99
100 pub fn next_id(&self) -> u64 {
118 let sequence = self.sequence.fetch_add(1, SeqCst) & SEQUENCE_MASK;
119 let mut new_timestamp = get_timestamp();
120 if sequence == 0 {
122 let last_timestamp = self.last_cycle_timestamp.load(Acquire);
123 if last_timestamp == new_timestamp {
124 self.wait_next_millis();
125 new_timestamp = get_timestamp();
126 }
127 self.last_cycle_timestamp.fetch_max(new_timestamp, Release);
128 }
129 (new_timestamp - EPOCH) << TIMESTAMP_SHIFT | sequence
130 }
131}
132#[cfg(any(test, feature = "for-test"))]
133pub fn into_parts(timestamp: u64) -> (u64, u64) {
134 (timestamp >> TIMESTAMP_SHIFT, timestamp & SEQUENCE_MASK)
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 fn wait_for_next_millis() {
143 std::thread::sleep(std::time::Duration::from_millis(1));
144 }
145
146 #[test]
147 fn test_next_generates_unique_ids() {
148 let timestamp_seq = TimestampSeq::new();
149
150 let id1 = timestamp_seq.next_id();
152 let id2 = timestamp_seq.next_id();
153 let id3 = timestamp_seq.next_id();
154
155 assert_ne!(id1, id2);
156 assert_ne!(id2, id3);
157 assert_ne!(id1, id3);
158 }
159
160 #[test]
161 fn test_next_increases_sequence() {
162 let timestamp_seq = TimestampSeq::new();
163
164 let id1 = timestamp_seq.next_id();
166 let id2 = timestamp_seq.next_id();
167
168 assert!(id2 > id1);
169 }
170
171 #[test]
172 fn test_next_does_not_repeat_ids() {
173 let timestamp_seq = TimestampSeq::new();
174
175 let id1 = timestamp_seq.next_id();
177 let id2 = timestamp_seq.next_id();
178 let id3 = timestamp_seq.next_id();
179 let id4 = timestamp_seq.next_id();
180
181 assert_ne!(id1, id2);
182 assert_ne!(id2, id3);
183 assert_ne!(id3, id4);
184 assert_ne!(id1, id4);
185 println!("{id1} {id2} {id3} {id4}");
186 println!(
187 "{:?} {:?} {:?} {:?}",
188 into_parts(id1),
189 into_parts(id2),
190 into_parts(id3),
191 into_parts(id4)
192 );
193 }
194
195 #[test]
196 fn test_next_wait_for_next_millis() {
197 let timestamp_seq = TimestampSeq::new();
198
199 let id1 = timestamp_seq.next_id();
201 wait_for_next_millis();
202 let id2 = timestamp_seq.next_id();
203
204 let timestamp1 = id1 >> TIMESTAMP_SHIFT;
205 let timestamp2 = id2 >> TIMESTAMP_SHIFT;
206
207 assert!(timestamp2 > timestamp1);
208 }
209}