Skip to main content

atomic_time/
system_time.rs

1use core::sync::atomic::Ordering;
2use std::time::SystemTime;
3
4use crate::AtomicDuration;
5
6/// An atomic version of [`std::time::SystemTime`].
7///
8/// Only [`SystemTime`] values at or after [`SystemTime::UNIX_EPOCH`] are supported.
9#[repr(transparent)]
10pub struct AtomicSystemTime(AtomicDuration);
11
12impl core::fmt::Debug for AtomicSystemTime {
13  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
14    f.debug_tuple("AtomicSystemTime")
15      .field(&self.load(Ordering::SeqCst))
16      .finish()
17  }
18}
19
20impl From<SystemTime> for AtomicSystemTime {
21  /// # Panics
22  ///
23  /// Panics if the given `SystemTime` value is earlier than [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
24  #[inline(always)]
25  fn from(system_time: SystemTime) -> Self {
26    Self::new(system_time)
27  }
28}
29
30impl AtomicSystemTime {
31  /// Returns the system time corresponding to "now".
32  ///
33  /// # Examples
34  /// ```
35  /// use atomic_time::AtomicSystemTime;
36  ///
37  /// let sys_time = AtomicSystemTime::now();
38  /// ```
39  #[inline(always)]
40  pub fn now() -> Self {
41    Self::new(SystemTime::now())
42  }
43
44  /// Creates a new `AtomicSystemTime` with the given `SystemTime` value.
45  ///
46  /// # Panics
47  ///
48  /// If the given `SystemTime` value is earlier than the [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
49  #[inline(always)]
50  pub fn new(system_time: SystemTime) -> Self {
51    Self(AtomicDuration::new(
52      system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
53    ))
54  }
55
56  /// Loads a value from the atomic system time.
57  #[inline(always)]
58  pub fn load(&self, order: Ordering) -> SystemTime {
59    SystemTime::UNIX_EPOCH + self.0.load(order)
60  }
61
62  /// Stores a value into the atomic system time.
63  ///
64  /// # Panics
65  ///
66  /// If the given `SystemTime` value is earlier than the [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
67  #[inline(always)]
68  pub fn store(&self, system_time: SystemTime, order: Ordering) {
69    self.0.store(
70      system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
71      order,
72    )
73  }
74
75  /// Stores a value into the atomic system time, returning the previous value.
76  ///
77  /// # Panics
78  ///
79  /// If the given `SystemTime` value is earlier than the [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
80  #[inline(always)]
81  pub fn swap(&self, system_time: SystemTime, order: Ordering) -> SystemTime {
82    SystemTime::UNIX_EPOCH
83      + self.0.swap(
84        system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
85        order,
86      )
87  }
88
89  /// Stores a value into the atomic system time if the current value is the same as the `current`
90  /// value.
91  ///
92  /// # Panics
93  ///
94  /// If the given `SystemTime` value is earlier than the [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
95  #[inline(always)]
96  pub fn compare_exchange(
97    &self,
98    current: SystemTime,
99    new: SystemTime,
100    success: Ordering,
101    failure: Ordering,
102  ) -> Result<SystemTime, SystemTime> {
103    match self.0.compare_exchange(
104      current.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
105      new.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
106      success,
107      failure,
108    ) {
109      Ok(duration) => Ok(SystemTime::UNIX_EPOCH + duration),
110      Err(duration) => Err(SystemTime::UNIX_EPOCH + duration),
111    }
112  }
113
114  /// Stores a value into the atomic system time if the current value is the same as the `current`
115  /// value.
116  ///
117  /// # Panics
118  ///
119  /// If the given `SystemTime` value is earlier than the [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
120  #[inline(always)]
121  pub fn compare_exchange_weak(
122    &self,
123    current: SystemTime,
124    new: SystemTime,
125    success: Ordering,
126    failure: Ordering,
127  ) -> Result<SystemTime, SystemTime> {
128    match self.0.compare_exchange_weak(
129      current.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
130      new.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
131      success,
132      failure,
133    ) {
134      Ok(duration) => Ok(SystemTime::UNIX_EPOCH + duration),
135      Err(duration) => Err(SystemTime::UNIX_EPOCH + duration),
136    }
137  }
138
139  /// Fetches the value and applies a function that can choose whether to store
140  /// a new value.
141  ///
142  /// Returns `Ok(previous_value)` when `f` returns `Some(_)`, and
143  /// `Err(previous_value)` when it returns `None`. The closure can run more
144  /// than once when another thread changes the value concurrently, but it is
145  /// applied only once to the value that is stored.
146  ///
147  /// `set_order` describes the ordering of the successful update and
148  /// `fetch_order` describes failed compare-and-exchange loads. They have the
149  /// same requirements as the success and failure orderings of
150  /// [`compare_exchange`](Self::compare_exchange).
151  ///
152  /// # Panics
153  ///
154  /// Panics if the orderings are invalid for
155  /// [`compare_exchange`](Self::compare_exchange), or if the function returns
156  /// a `SystemTime` value earlier than [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
157  ///
158  /// # Examples
159  ///
160  /// ```rust
161  /// use atomic_time::AtomicSystemTime;
162  /// use std::{sync::atomic::Ordering, time::{Duration, SystemTime}};
163  ///
164  /// let start = SystemTime::UNIX_EPOCH + Duration::from_secs(7);
165  /// let x = AtomicSystemTime::new(start);
166  /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(start));
167  /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + Duration::from_secs(1))), Ok(start));
168  /// ```
169  #[inline(always)]
170  pub fn try_update<F>(
171    &self,
172    set_order: Ordering,
173    fetch_order: Ordering,
174    mut f: F,
175  ) -> Result<SystemTime, SystemTime>
176  where
177    F: FnMut(SystemTime) -> Option<SystemTime>,
178  {
179    self
180      .0
181      .try_update(set_order, fetch_order, |duration| {
182        f(SystemTime::UNIX_EPOCH + duration)
183          .map(|system_time| system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap())
184      })
185      .map(|duration| SystemTime::UNIX_EPOCH + duration)
186      .map_err(|duration| SystemTime::UNIX_EPOCH + duration)
187  }
188
189  /// Fetches the value, and applies a function to it that returns an optional
190  /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
191  /// `Err(previous_value)`.
192  ///
193  /// Note: This may call the function multiple times if the value has been changed from other threads in
194  /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
195  /// only once to the stored value.
196  ///
197  /// `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
198  /// The first describes the required ordering for when the operation finally succeeds while the second
199  /// describes the required ordering for loads. These correspond to the success and failure orderings of
200  /// [`compare_exchange`] respectively.
201  ///
202  /// Using [`Acquire`](Ordering::Acquire) as success ordering makes the store part
203  /// of this operation [`Relaxed`](Ordering::Relaxed), and using [`Release`](Ordering::Release) makes the final successful load
204  /// [`Relaxed`](Ordering::Relaxed). The (failed) load ordering can only be [`SeqCst`](Ordering::SeqCst), [`Acquire`](Ordering::Acquire) or [`Relaxed`](Ordering::Relaxed)
205  /// and must be equivalent to or weaker than the success ordering.
206  ///
207  /// [`compare_exchange`]: #method.compare_exchange
208  ///
209  /// # Panics
210  ///
211  /// If the given `SystemTime` value is earlier than the [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
212  ///
213  /// # Examples
214  ///
215  /// ```rust
216  /// use atomic_time::AtomicSystemTime;
217  /// use std::{time::{Duration, SystemTime}, sync::atomic::Ordering};
218  ///
219  /// let now = SystemTime::now();
220  /// let x = AtomicSystemTime::new(now);
221  /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(now));
222  ///
223  /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + Duration::from_secs(1))), Ok(now));
224  /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + Duration::from_secs(1))), Ok(now + Duration::from_secs(1)));
225  /// assert_eq!(x.load(Ordering::SeqCst), now + Duration::from_secs(2));
226  /// ```
227  #[inline(always)]
228  pub fn fetch_update<F>(
229    &self,
230    set_order: Ordering,
231    fetch_order: Ordering,
232    f: F,
233  ) -> Result<SystemTime, SystemTime>
234  where
235    F: FnMut(SystemTime) -> Option<SystemTime>,
236  {
237    self.try_update(set_order, fetch_order, f)
238  }
239
240  /// Fetches the value, applies a function to produce a new value, stores it,
241  /// and returns the previous value.
242  ///
243  /// The closure can run more than once when another thread changes the value
244  /// concurrently, but it is applied only once to the value that is stored.
245  /// `set_order` and `fetch_order` have the same requirements as the success
246  /// and failure orderings of [`compare_exchange`](Self::compare_exchange).
247  ///
248  /// # Panics
249  ///
250  /// Panics if the orderings are invalid for
251  /// [`compare_exchange`](Self::compare_exchange), or if the function returns
252  /// a `SystemTime` value earlier than [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
253  ///
254  /// # Examples
255  ///
256  /// ```rust
257  /// use atomic_time::AtomicSystemTime;
258  /// use std::{sync::atomic::Ordering, time::{Duration, SystemTime}};
259  ///
260  /// let start = SystemTime::UNIX_EPOCH + Duration::from_secs(7);
261  /// let x = AtomicSystemTime::new(start);
262  /// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |old| old + Duration::from_secs(1)), start);
263  /// assert_eq!(x.load(Ordering::SeqCst), start + Duration::from_secs(1));
264  /// ```
265  #[inline(always)]
266  pub fn update<F>(&self, set_order: Ordering, fetch_order: Ordering, mut f: F) -> SystemTime
267  where
268    F: FnMut(SystemTime) -> SystemTime,
269  {
270    SystemTime::UNIX_EPOCH
271      + self.0.update(set_order, fetch_order, |duration| {
272        f(SystemTime::UNIX_EPOCH + duration)
273          .duration_since(SystemTime::UNIX_EPOCH)
274          .unwrap()
275      })
276  }
277
278  /// Atomically stores the smaller of the current value and `val`, returning
279  /// the previous value.
280  ///
281  /// Values are ordered by their duration from [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
282  /// `order` describes the memory ordering of the read-modify-write operation.
283  /// Using [`Acquire`](Ordering::Acquire) makes its store part relaxed, and
284  /// using [`Release`](Ordering::Release) makes its load part relaxed.
285  ///
286  /// # Panics
287  ///
288  /// Panics if `val` is earlier than [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
289  ///
290  /// # Examples
291  ///
292  /// ```rust
293  /// use atomic_time::AtomicSystemTime;
294  /// use std::{sync::atomic::Ordering, time::{Duration, SystemTime}};
295  ///
296  /// let start = SystemTime::UNIX_EPOCH + Duration::from_secs(5);
297  /// let x = AtomicSystemTime::new(start);
298  /// assert_eq!(x.fetch_min(start + Duration::from_secs(2), Ordering::SeqCst), start);
299  /// assert_eq!(x.fetch_min(start - Duration::from_secs(1), Ordering::SeqCst), start);
300  /// assert_eq!(x.load(Ordering::SeqCst), start - Duration::from_secs(1));
301  /// ```
302  #[inline(always)]
303  pub fn fetch_min(&self, val: SystemTime, order: Ordering) -> SystemTime {
304    SystemTime::UNIX_EPOCH
305      + self
306        .0
307        .fetch_min(val.duration_since(SystemTime::UNIX_EPOCH).unwrap(), order)
308  }
309
310  /// Atomically stores the larger of the current value and `val`, returning
311  /// the previous value.
312  ///
313  /// Values are ordered by their duration from [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
314  /// `order` describes the memory ordering of the read-modify-write operation.
315  /// Using [`Acquire`](Ordering::Acquire) makes its store part relaxed, and
316  /// using [`Release`](Ordering::Release) makes its load part relaxed.
317  ///
318  /// # Panics
319  ///
320  /// Panics if `val` is earlier than [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
321  ///
322  /// # Examples
323  ///
324  /// ```rust
325  /// use atomic_time::AtomicSystemTime;
326  /// use std::{sync::atomic::Ordering, time::{Duration, SystemTime}};
327  ///
328  /// let start = SystemTime::UNIX_EPOCH + Duration::from_secs(5);
329  /// let x = AtomicSystemTime::new(start);
330  /// assert_eq!(x.fetch_max(start - Duration::from_secs(2), Ordering::SeqCst), start);
331  /// assert_eq!(x.fetch_max(start + Duration::from_secs(1), Ordering::SeqCst), start);
332  /// assert_eq!(x.load(Ordering::SeqCst), start + Duration::from_secs(1));
333  /// ```
334  #[inline(always)]
335  pub fn fetch_max(&self, val: SystemTime, order: Ordering) -> SystemTime {
336    SystemTime::UNIX_EPOCH
337      + self
338        .0
339        .fetch_max(val.duration_since(SystemTime::UNIX_EPOCH).unwrap(), order)
340  }
341
342  /// Returns `true` if operations on values of this type are lock-free.
343  /// If the compiler or the platform doesn't support the necessary
344  /// atomic instructions, global locks for every potentially
345  /// concurrent atomic operation will be used.
346  ///
347  /// # Examples
348  /// ```
349  /// use atomic_time::AtomicSystemTime;
350  ///
351  /// let is_lock_free = AtomicSystemTime::is_lock_free();
352  /// ```
353  #[inline(always)]
354  pub fn is_lock_free() -> bool {
355    AtomicDuration::is_lock_free()
356  }
357
358  /// Returns whether operations on values of this type are always lock-free.
359  ///
360  /// A `false` result does not preclude lock-free operations selected through
361  /// runtime CPU feature detection; use [`is_lock_free`](Self::is_lock_free)
362  /// to query the current target at runtime.
363  ///
364  /// # Examples
365  ///
366  /// ```rust
367  /// use atomic_time::AtomicSystemTime;
368  ///
369  /// const ALWAYS_LOCK_FREE: bool = AtomicSystemTime::is_always_lock_free();
370  /// let _ = ALWAYS_LOCK_FREE;
371  /// ```
372  #[inline(always)]
373  pub const fn is_always_lock_free() -> bool {
374    AtomicDuration::is_always_lock_free()
375  }
376
377  /// Consumes the atomic and returns the contained value.
378  ///
379  /// This is safe because passing `self` by value guarantees that no other threads are
380  /// concurrently accessing the atomic data.
381  #[inline(always)]
382  pub fn into_inner(self) -> SystemTime {
383    SystemTime::UNIX_EPOCH + self.0.into_inner()
384  }
385}
386
387#[cfg(feature = "serde")]
388const _: () = {
389  use serde::{Deserialize, Serialize};
390
391  impl Serialize for AtomicSystemTime {
392    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
393      self.load(Ordering::SeqCst).serialize(serializer)
394    }
395  }
396
397  impl<'de> Deserialize<'de> for AtomicSystemTime {
398    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
399      Ok(Self::new(SystemTime::deserialize(deserializer)?))
400    }
401  }
402};
403
404#[cfg(test)]
405mod tests {
406  use super::*;
407  use std::time::Duration;
408
409  #[test]
410  fn test_atomic_system_time_now() {
411    let atomic_time = AtomicSystemTime::now();
412    // As SystemTime::now is very precise, this test needs to be lenient with timing.
413    // Just check that the time is not the UNIX_EPOCH.
414    assert_ne!(atomic_time.load(Ordering::SeqCst), SystemTime::UNIX_EPOCH);
415  }
416
417  #[test]
418  fn test_atomic_system_time_new_and_load() {
419    let now = SystemTime::now();
420    let atomic_time = AtomicSystemTime::new(now);
421    assert_eq!(atomic_time.load(Ordering::SeqCst), now);
422  }
423
424  #[test]
425  fn test_atomic_system_time_store_and_load() {
426    let now = SystemTime::now();
427    let after_one_sec = now + Duration::from_secs(1);
428    let atomic_time = AtomicSystemTime::new(now);
429    atomic_time.store(after_one_sec, Ordering::SeqCst);
430    assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
431  }
432
433  #[test]
434  fn test_atomic_system_time_swap() {
435    let now = SystemTime::now();
436    let after_one_sec = now + Duration::from_secs(1);
437    let atomic_time = AtomicSystemTime::new(now);
438    let prev_time = atomic_time.swap(after_one_sec, Ordering::SeqCst);
439    assert_eq!(prev_time, now);
440    assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
441  }
442
443  #[test]
444  fn test_atomic_system_time_compare_exchange_weak() {
445    let now = SystemTime::now();
446    let after_one_sec = now + Duration::from_secs(1);
447    let after_two_secs = now + Duration::from_secs(2);
448    let atomic_time = AtomicSystemTime::new(now);
449
450    // Successful compare_exchange_weak
451    let mut result;
452    loop {
453      result =
454        atomic_time.compare_exchange_weak(now, after_one_sec, Ordering::SeqCst, Ordering::SeqCst);
455      if result.is_ok() {
456        break;
457      }
458    }
459    assert!(result.is_ok());
460    assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
461
462    // Failed compare_exchange_weak
463    let result =
464      atomic_time.compare_exchange_weak(now, after_two_secs, Ordering::SeqCst, Ordering::SeqCst);
465    assert!(result.is_err());
466    assert_eq!(result.unwrap_err(), after_one_sec);
467  }
468
469  #[test]
470  fn test_atomic_system_time_compare_exchange() {
471    let now = SystemTime::now();
472    let after_one_sec = now + Duration::from_secs(1);
473    let atomic_time = AtomicSystemTime::new(now);
474    let result =
475      atomic_time.compare_exchange(now, after_one_sec, Ordering::SeqCst, Ordering::SeqCst);
476    assert!(result.is_ok());
477    assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
478  }
479
480  #[test]
481  fn test_atomic_system_time_fetch_update() {
482    let now = SystemTime::now();
483    let atomic_time = AtomicSystemTime::new(now);
484
485    // Update the time by adding 1 second
486    let result = atomic_time.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
487      Some(prev + Duration::from_secs(1))
488    });
489    assert!(result.is_ok());
490    assert_eq!(result.unwrap(), now);
491    assert_eq!(
492      atomic_time.load(Ordering::SeqCst),
493      now + Duration::from_secs(1)
494    );
495
496    // Trying an update that returns None, should not change the value
497    let result = atomic_time.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None);
498    assert!(result.is_err());
499    assert_eq!(result.unwrap_err(), now + Duration::from_secs(1));
500    assert_eq!(
501      atomic_time.load(Ordering::SeqCst),
502      now + Duration::from_secs(1)
503    );
504  }
505
506  #[test]
507  fn test_atomic_system_time_try_update() {
508    let start = SystemTime::UNIX_EPOCH + Duration::from_secs(10);
509    let atomic_time = AtomicSystemTime::new(start);
510
511    assert_eq!(
512      atomic_time.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None),
513      Err(start)
514    );
515    assert_eq!(
516      atomic_time.try_update(Ordering::SeqCst, Ordering::SeqCst, |current| {
517        Some(current + Duration::from_secs(2))
518      }),
519      Ok(start)
520    );
521    assert_eq!(
522      atomic_time.load(Ordering::SeqCst),
523      start + Duration::from_secs(2)
524    );
525  }
526
527  #[test]
528  fn test_atomic_system_time_update_returns_previous_value() {
529    let start = SystemTime::UNIX_EPOCH + Duration::from_secs(10);
530    let atomic_time = AtomicSystemTime::new(start);
531
532    assert_eq!(
533      atomic_time.update(Ordering::SeqCst, Ordering::SeqCst, |current| {
534        current + Duration::from_secs(2)
535      }),
536      start
537    );
538    assert_eq!(
539      atomic_time.load(Ordering::SeqCst),
540      start + Duration::from_secs(2)
541    );
542  }
543
544  #[test]
545  fn test_atomic_system_time_fetch_min_and_max() {
546    let low = SystemTime::UNIX_EPOCH + Duration::from_secs(10);
547    let middle = low + Duration::from_secs(5);
548    let high = middle + Duration::from_secs(5);
549    let atomic_time = AtomicSystemTime::new(middle);
550
551    assert_eq!(atomic_time.fetch_min(high, Ordering::SeqCst), middle);
552    assert_eq!(atomic_time.load(Ordering::SeqCst), middle);
553    assert_eq!(atomic_time.fetch_min(middle, Ordering::SeqCst), middle);
554    assert_eq!(atomic_time.load(Ordering::SeqCst), middle);
555    assert_eq!(atomic_time.fetch_min(low, Ordering::SeqCst), middle);
556    assert_eq!(atomic_time.load(Ordering::SeqCst), low);
557
558    atomic_time.store(middle, Ordering::SeqCst);
559    assert_eq!(atomic_time.fetch_max(low, Ordering::SeqCst), middle);
560    assert_eq!(atomic_time.load(Ordering::SeqCst), middle);
561    assert_eq!(atomic_time.fetch_max(middle, Ordering::SeqCst), middle);
562    assert_eq!(atomic_time.load(Ordering::SeqCst), middle);
563    assert_eq!(atomic_time.fetch_max(high, Ordering::SeqCst), middle);
564    assert_eq!(atomic_time.load(Ordering::SeqCst), high);
565  }
566
567  #[test]
568  fn test_atomic_system_time_always_lock_free_implies_lock_free() {
569    assert!(!AtomicSystemTime::is_always_lock_free() || AtomicSystemTime::is_lock_free());
570  }
571
572  #[test]
573  #[should_panic]
574  fn test_atomic_system_time_fetch_min_before_epoch_panics() {
575    let atomic_time = AtomicSystemTime::new(SystemTime::UNIX_EPOCH);
576    atomic_time.fetch_min(
577      SystemTime::UNIX_EPOCH - Duration::from_secs(1),
578      Ordering::SeqCst,
579    );
580  }
581
582  #[test]
583  #[cfg(feature = "std")]
584  fn test_atomic_system_time_thread_safety() {
585    use std::sync::Arc;
586    use std::thread;
587
588    // Start from a fixed, known value so we can assert an *exact*
589    // final result. The previous version used `load + add + store`,
590    // which loses updates under contention, and asserted only that
591    // the final time was in the future — true even if every
592    // concurrent update was dropped.
593    let start = SystemTime::now();
594    let atomic_time = Arc::new(AtomicSystemTime::new(start));
595    let mut handles = vec![];
596
597    for _ in 0..4 {
598      let atomic_clone = atomic_time.clone();
599      let handle = thread::spawn(move || {
600        atomic_clone
601          .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |current| {
602            Some(current + Duration::from_secs(1))
603          })
604          .expect("closure never returns None");
605      });
606      handles.push(handle);
607    }
608
609    for handle in handles {
610      handle.join().unwrap();
611    }
612
613    // 4 threads × 1 second = 4 seconds, no lost updates.
614    assert_eq!(
615      atomic_time.load(Ordering::SeqCst),
616      start + Duration::from_secs(4)
617    );
618  }
619
620  #[test]
621  fn test_atomic_system_time_debug() {
622    let atomic_time = AtomicSystemTime::now();
623    let debug_str = format!("{:?}", atomic_time);
624    assert!(debug_str.contains("AtomicSystemTime"));
625  }
626
627  #[test]
628  fn test_atomic_system_time_from() {
629    let now = SystemTime::now();
630    let atomic_time = AtomicSystemTime::from(now);
631    assert_eq!(atomic_time.load(Ordering::SeqCst), now);
632  }
633
634  #[test]
635  fn test_atomic_system_time_into_inner() {
636    let now = SystemTime::now();
637    let atomic_time = AtomicSystemTime::new(now);
638    assert_eq!(atomic_time.into_inner(), now);
639  }
640
641  #[test]
642  fn test_atomic_system_time_compare_exchange_failure() {
643    let now = SystemTime::now();
644    let other = now + Duration::from_secs(5);
645    let atomic_time = AtomicSystemTime::new(now);
646    let result = atomic_time.compare_exchange(other, other, Ordering::SeqCst, Ordering::SeqCst);
647    assert!(result.is_err());
648    assert_eq!(result.unwrap_err(), now);
649  }
650
651  #[test]
652  fn test_atomic_system_time_compare_exchange_weak_failure() {
653    let now = SystemTime::now();
654    let other = now + Duration::from_secs(5);
655    let atomic_time = AtomicSystemTime::new(now);
656    let result =
657      atomic_time.compare_exchange_weak(other, other, Ordering::SeqCst, Ordering::SeqCst);
658    assert!(result.is_err());
659    assert_eq!(result.unwrap_err(), now);
660  }
661
662  #[cfg(feature = "serde")]
663  #[test]
664  fn test_atomic_system_time_serde() {
665    let now = SystemTime::now();
666    let atomic = AtomicSystemTime::new(now);
667    let serialized = serde_json::to_string(&atomic).unwrap();
668    let deserialized: AtomicSystemTime = serde_json::from_str(&serialized).unwrap();
669    assert_eq!(deserialized.load(Ordering::SeqCst), now,);
670  }
671}