1use std::time::Instant;
2
3use super::*;
4
5#[repr(transparent)]
7pub struct AtomicInstant(AtomicDuration);
8
9impl AtomicInstant {
10 pub fn now() -> Self {
19 Self::new(Instant::now())
20 }
21
22 pub fn new(instant: Instant) -> Self {
24 Self(AtomicDuration::new(encode_instant_to_duration(instant)))
25 }
26
27 pub fn load(&self, order: Ordering) -> Instant {
29 decode_instant_from_duration(self.0.load(order))
30 }
31
32 pub fn store(&self, instant: Instant, order: Ordering) {
34 self.0.store(encode_instant_to_duration(instant), order)
35 }
36
37 pub fn swap(&self, instant: Instant, order: Ordering) -> Instant {
39 decode_instant_from_duration(self.0.swap(encode_instant_to_duration(instant), order))
40 }
41
42 pub fn compare_exchange(
45 &self,
46 current: Instant,
47 new: Instant,
48 success: Ordering,
49 failure: Ordering,
50 ) -> Result<Instant, Instant> {
51 match self.0.compare_exchange(
52 encode_instant_to_duration(current),
53 encode_instant_to_duration(new),
54 success,
55 failure,
56 ) {
57 Ok(duration) => Ok(decode_instant_from_duration(duration)),
58 Err(duration) => Err(decode_instant_from_duration(duration)),
59 }
60 }
61
62 pub fn compare_exchange_weak(
65 &self,
66 current: Instant,
67 new: Instant,
68 success: Ordering,
69 failure: Ordering,
70 ) -> Result<Instant, Instant> {
71 match self.0.compare_exchange_weak(
72 encode_instant_to_duration(current),
73 encode_instant_to_duration(new),
74 success,
75 failure,
76 ) {
77 Ok(duration) => Ok(decode_instant_from_duration(duration)),
78 Err(duration) => Err(decode_instant_from_duration(duration)),
79 }
80 }
81
82 pub fn fetch_update<F>(
117 &self,
118 set_order: Ordering,
119 fetch_order: Ordering,
120 mut f: F,
121 ) -> Result<Instant, Instant>
122 where
123 F: FnMut(Instant) -> Option<Instant>,
124 {
125 self
126 .0
127 .fetch_update(set_order, fetch_order, |duration| {
128 f(decode_instant_from_duration(duration)).map(encode_instant_to_duration)
129 })
130 .map(decode_instant_from_duration)
131 .map_err(decode_instant_from_duration)
132 }
133
134 #[inline]
146 pub fn is_lock_free() -> bool {
147 AtomicU128::is_lock_free()
148 }
149}
150
151#[cfg(feature = "serde")]
152const _: () = {
153 use core::time::Duration;
154 use serde::{Deserialize, Serialize};
155
156 impl Serialize for AtomicInstant {
157 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
158 self.0.load(Ordering::SeqCst).serialize(serializer)
159 }
160 }
161
162 impl<'de> Deserialize<'de> for AtomicInstant {
163 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
164 Ok(Self::new(decode_instant_from_duration(
165 Duration::deserialize(deserializer)?,
166 )))
167 }
168 }
169};
170
171#[cfg(test)]
172mod tests {
173 use super::*;
174 use std::time::Duration;
175
176 #[test]
177 fn test_atomic_instant_now() {
178 let atomic_instant = AtomicInstant::now();
179 let now = Instant::now();
181 let loaded_instant = atomic_instant.load(Ordering::SeqCst);
182 assert!(loaded_instant <= now);
183 assert!(loaded_instant >= now - Duration::from_secs(1));
184 }
185
186 #[test]
187 fn test_atomic_instant_new_and_load() {
188 let now = Instant::now();
189 let atomic_instant = AtomicInstant::new(now);
190 assert_eq!(atomic_instant.load(Ordering::SeqCst), now);
191 }
192
193 #[test]
194 fn test_atomic_instant_store_and_load() {
195 let now = Instant::now();
196 let after_one_sec = now + Duration::from_secs(1);
197 let atomic_instant = AtomicInstant::new(now);
198 atomic_instant.store(after_one_sec, Ordering::SeqCst);
199 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
200 }
201
202 #[test]
203 fn test_atomic_instant_swap() {
204 let now = Instant::now();
205 let after_one_sec = now + Duration::from_secs(1);
206 let atomic_instant = AtomicInstant::new(now);
207 let prev_instant = atomic_instant.swap(after_one_sec, Ordering::SeqCst);
208 assert_eq!(prev_instant, now);
209 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
210 }
211
212 #[test]
213 fn test_atomic_instant_compare_exchange() {
214 let now = Instant::now();
215 let after_one_sec = now + Duration::from_secs(1);
216 let atomic_instant = AtomicInstant::new(now);
217 let result =
218 atomic_instant.compare_exchange(now, after_one_sec, Ordering::SeqCst, Ordering::SeqCst);
219 assert!(result.is_ok());
220 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
221 }
222
223 #[test]
224 fn test_atomic_instant_compare_exchange_weak() {
225 let now = Instant::now();
226 let after_one_sec = now + Duration::from_secs(1);
227 let atomic_instant = AtomicInstant::new(now);
228
229 let mut result;
230 loop {
231 result = atomic_instant.compare_exchange_weak(
232 now,
233 after_one_sec,
234 Ordering::SeqCst,
235 Ordering::SeqCst,
236 );
237 if result.is_ok() {
238 break;
239 }
240 }
241 assert!(result.is_ok());
242 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
243 }
244
245 #[test]
246 fn test_atomic_instant_fetch_update() {
247 let now = Instant::now();
248 let atomic_instant = AtomicInstant::new(now);
249
250 let result = atomic_instant.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
251 Some(prev + Duration::from_secs(1))
252 });
253 assert!(result.is_ok());
254 assert_eq!(result.unwrap(), now);
255 assert_eq!(
256 atomic_instant.load(Ordering::SeqCst),
257 now + Duration::from_secs(1)
258 );
259 }
260
261 #[test]
262 fn test_atomic_instant_thread_safety() {
263 use std::sync::Arc;
264 use std::thread;
265
266 let atomic_instant = Arc::new(AtomicInstant::now());
267 let mut handles = vec![];
268
269 for _ in 0..4 {
270 let atomic_clone = atomic_instant.clone();
271 let handle = thread::spawn(move || {
272 let current = atomic_clone.load(Ordering::SeqCst);
273 let new = current + Duration::from_millis(50);
274 atomic_clone.store(new, Ordering::SeqCst);
275 });
276 handles.push(handle);
277 }
278
279 for handle in handles {
280 handle.join().unwrap();
281 }
282
283 let loaded_instant = atomic_instant.load(Ordering::SeqCst);
285 assert!(loaded_instant >= Instant::now() - Duration::from_millis(200));
286 }
287
288 #[cfg(feature = "serde")]
289 #[test]
290 fn test_atomic_instant_serde() {
291 use serde::{Deserialize, Serialize};
292
293 #[derive(Serialize, Deserialize)]
294 struct Test {
295 time: AtomicInstant,
296 }
297
298 let now = Instant::now();
299 let test = Test {
300 time: AtomicInstant::new(now),
301 };
302 let serialized = serde_json::to_string(&test).unwrap();
303 let deserialized: Test = serde_json::from_str(&serialized).unwrap();
304 assert_eq!(deserialized.time.load(Ordering::SeqCst), now);
305 }
306}