Skip to main content

atomic_time/
duration.rs

1use crate::AtomicU128;
2use core::{sync::atomic::Ordering, time::Duration};
3
4/// Atomic version of [`Duration`]
5#[repr(transparent)]
6pub struct AtomicDuration(AtomicU128);
7impl core::fmt::Debug for AtomicDuration {
8  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
9    f.debug_tuple("AtomicDuration")
10      .field(&self.load(Ordering::SeqCst))
11      .finish()
12  }
13}
14impl Default for AtomicDuration {
15  /// Creates an `AtomicDuration` initialized to [`Duration::ZERO`].
16  #[inline(always)]
17  fn default() -> Self {
18    Self::new(Duration::ZERO)
19  }
20}
21impl From<Duration> for AtomicDuration {
22  #[inline(always)]
23  fn from(duration: Duration) -> Self {
24    Self::new(duration)
25  }
26}
27impl AtomicDuration {
28  /// Creates a new `AtomicDuration` with the given value.
29  #[inline(always)]
30  pub const fn new(duration: Duration) -> Self {
31    Self(AtomicU128::new(encode_duration(duration)))
32  }
33  /// Loads [`Duration`](Duration) from `AtomicDuration`.
34  ///
35  /// load takes an [`Ordering`] argument which describes the memory ordering of this operation.
36  ///
37  /// # Panics
38  /// Panics if order is [`Release`](Ordering::Release) or [`AcqRel`](Ordering::AcqRel).
39  #[inline(always)]
40  pub fn load(&self, ordering: Ordering) -> Duration {
41    decode_duration(self.0.load(ordering))
42  }
43  /// Stores a value into the `AtomicDuration`.
44  ///
45  /// `store` takes an [`Ordering`] argument which describes the memory ordering
46  /// of this operation.
47  ///
48  /// # Panics
49  ///
50  /// Panics if `order` is [`Acquire`](Ordering::Acquire) or [`AcqRel`](Ordering::AcqRel).
51  #[inline(always)]
52  pub fn store(&self, val: Duration, ordering: Ordering) {
53    self.0.store(encode_duration(val), ordering)
54  }
55  /// Stores a value into the `AtomicDuration`, returning the old value.
56  ///
57  /// `swap` takes an [`Ordering`] argument which describes the memory ordering
58  /// of this operation.
59  #[inline(always)]
60  pub fn swap(&self, val: Duration, ordering: Ordering) -> Duration {
61    decode_duration(self.0.swap(encode_duration(val), ordering))
62  }
63  /// Stores a value into the `AtomicDuration` if the current value is the same as the
64  /// `current` value.
65  ///
66  /// Unlike [`compare_exchange`], this function is allowed to spuriously fail
67  /// even when the comparison succeeds, which can result in more efficient
68  /// code on some platforms. The return value is a result indicating whether
69  /// the new value was written and containing the previous value.
70  ///
71  /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
72  /// ordering of this operation. The first describes the required ordering if
73  /// the operation succeeds while the second describes the required ordering
74  /// when the operation fails. The failure ordering can't be [`Release`](Ordering::Release) or
75  /// [`AcqRel`](Ordering::AcqRel) and must be equivalent or weaker than the success ordering.
76  /// success ordering.
77  ///
78  /// [`compare_exchange`]: #method.compare_exchange
79  #[inline(always)]
80  pub fn compare_exchange_weak(
81    &self,
82    current: Duration,
83    new: Duration,
84    success: Ordering,
85    failure: Ordering,
86  ) -> Result<Duration, Duration> {
87    self
88      .0
89      .compare_exchange_weak(
90        encode_duration(current),
91        encode_duration(new),
92        success,
93        failure,
94      )
95      .map(decode_duration)
96      .map_err(decode_duration)
97  }
98  /// Stores a value into the `AtomicDuration` if the current value is the same as the
99  /// `current` value.
100  ///
101  /// The return value is a result indicating whether the new value was
102  /// written and containing the previous value. On success this value is
103  /// guaranteed to be equal to `current`.
104  ///
105  /// [`compare_exchange`] takes two [`Ordering`] arguments to describe the memory
106  /// ordering of this operation. The first describes the required ordering if
107  /// the operation succeeds while the second describes the required ordering
108  /// when the operation fails. The failure ordering can't be [`Release`](Ordering::Release) or
109  /// [`AcqRel`](Ordering::AcqRel) and must be equivalent or weaker than the success ordering.
110  ///
111  /// [`compare_exchange`]: #method.compare_exchange
112  #[inline(always)]
113  pub fn compare_exchange(
114    &self,
115    current: Duration,
116    new: Duration,
117    success: Ordering,
118    failure: Ordering,
119  ) -> Result<Duration, Duration> {
120    self
121      .0
122      .compare_exchange(
123        encode_duration(current),
124        encode_duration(new),
125        success,
126        failure,
127      )
128      .map(decode_duration)
129      .map_err(decode_duration)
130  }
131  /// Fetches the value and applies a function that can choose whether to store
132  /// a new value.
133  ///
134  /// Returns `Ok(previous_value)` when `f` returns `Some(_)`, and
135  /// `Err(previous_value)` when it returns `None`. The closure can run more
136  /// than once when another thread changes the value concurrently, but it is
137  /// applied only once to the value that is stored.
138  ///
139  /// `set_order` describes the ordering of the successful update and
140  /// `fetch_order` describes failed compare-and-exchange loads. They have the
141  /// same requirements as the success and failure orderings of
142  /// [`compare_exchange`](Self::compare_exchange).
143  ///
144  /// # Panics
145  ///
146  /// Panics if the orderings are invalid for
147  /// [`compare_exchange`](Self::compare_exchange).
148  ///
149  /// # Examples
150  ///
151  /// ```rust
152  /// use atomic_time::AtomicDuration;
153  /// use std::{sync::atomic::Ordering, time::Duration};
154  ///
155  /// let x = AtomicDuration::new(Duration::from_secs(7));
156  /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(Duration::from_secs(7)));
157  /// assert_eq!(x.try_update(Ordering::SeqCst, Ordering::SeqCst, |old| Some(old + Duration::from_secs(1))), Ok(Duration::from_secs(7)));
158  /// ```
159  #[inline(always)]
160  pub fn try_update<F>(
161    &self,
162    set_order: Ordering,
163    fetch_order: Ordering,
164    mut f: F,
165  ) -> Result<Duration, Duration>
166  where
167    F: FnMut(Duration) -> Option<Duration>,
168  {
169    self
170      .0
171      .fetch_update(set_order, fetch_order, |d| {
172        f(decode_duration(d)).map(encode_duration)
173      })
174      .map(decode_duration)
175      .map_err(decode_duration)
176  }
177  /// Fetches the value, and applies a function to it that returns an optional
178  /// new value. Returns a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
179  /// `Err(previous_value)`.
180  ///
181  /// Note: This may call the function multiple times if the value has been changed from other threads in
182  /// the meantime, as long as the function returns `Some(_)`, but the function will have been applied
183  /// only once to the stored value.
184  ///
185  /// `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation.
186  /// The first describes the required ordering for when the operation finally succeeds while the second
187  /// describes the required ordering for loads. These correspond to the success and failure orderings of
188  /// [`compare_exchange`] respectively.
189  ///
190  /// Using [`Acquire`](Ordering::Acquire) as success ordering makes the store part
191  /// of this operation [`Relaxed`](Ordering::Relaxed), and using [`Release`](Ordering::Release) makes the final successful load
192  /// [`Relaxed`](Ordering::Relaxed). The (failed) load ordering can only be [`SeqCst`](Ordering::SeqCst), [`Acquire`](Ordering::Acquire) or [`Relaxed`](Ordering::Relaxed)
193  /// and must be equivalent to or weaker than the success ordering.
194  ///
195  /// [`compare_exchange`]: #method.compare_exchange
196  ///
197  /// # Examples
198  ///
199  /// ```rust
200  /// use atomic_time::AtomicDuration;
201  /// use std::{time::Duration, sync::atomic::Ordering};
202  ///
203  /// let x = AtomicDuration::new(Duration::from_secs(7));
204  /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(Duration::from_secs(7)));
205  /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + Duration::from_secs(1))), Ok(Duration::from_secs(7)));
206  /// assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + Duration::from_secs(1))), Ok(Duration::from_secs(8)));
207  /// assert_eq!(x.load(Ordering::SeqCst), Duration::from_secs(9));
208  /// ```
209  #[inline(always)]
210  pub fn fetch_update<F>(
211    &self,
212    set_order: Ordering,
213    fetch_order: Ordering,
214    f: F,
215  ) -> Result<Duration, Duration>
216  where
217    F: FnMut(Duration) -> Option<Duration>,
218  {
219    self.try_update(set_order, fetch_order, f)
220  }
221
222  /// Fetches the value, applies a function to produce a new value, stores it,
223  /// and returns the previous value.
224  ///
225  /// The closure can run more than once when another thread changes the value
226  /// concurrently, but it is applied only once to the value that is stored.
227  /// `set_order` and `fetch_order` have the same requirements as the success
228  /// and failure orderings of [`compare_exchange`](Self::compare_exchange).
229  ///
230  /// # Panics
231  ///
232  /// Panics if the orderings are invalid for
233  /// [`compare_exchange`](Self::compare_exchange).
234  ///
235  /// # Examples
236  ///
237  /// ```rust
238  /// use atomic_time::AtomicDuration;
239  /// use std::{sync::atomic::Ordering, time::Duration};
240  ///
241  /// let x = AtomicDuration::new(Duration::from_secs(7));
242  /// assert_eq!(x.update(Ordering::SeqCst, Ordering::SeqCst, |old| old + Duration::from_secs(1)), Duration::from_secs(7));
243  /// assert_eq!(x.load(Ordering::SeqCst), Duration::from_secs(8));
244  /// ```
245  #[inline(always)]
246  pub fn update<F>(&self, set_order: Ordering, fetch_order: Ordering, mut f: F) -> Duration
247  where
248    F: FnMut(Duration) -> Duration,
249  {
250    let mut current = self.0.load(fetch_order);
251    loop {
252      let new = encode_duration(f(decode_duration(current)));
253      match self
254        .0
255        .compare_exchange_weak(current, new, set_order, fetch_order)
256      {
257        Ok(previous) => return decode_duration(previous),
258        Err(actual) => current = actual,
259      }
260    }
261  }
262
263  /// Atomically stores the smaller of the current value and `val`, returning
264  /// the previous value.
265  ///
266  /// `order` describes the memory ordering of the read-modify-write operation.
267  /// Using [`Acquire`](Ordering::Acquire) makes its store part relaxed, and
268  /// using [`Release`](Ordering::Release) makes its load part relaxed.
269  ///
270  /// # Examples
271  ///
272  /// ```rust
273  /// use atomic_time::AtomicDuration;
274  /// use std::{sync::atomic::Ordering, time::Duration};
275  ///
276  /// let x = AtomicDuration::new(Duration::from_secs(7));
277  /// assert_eq!(x.fetch_min(Duration::from_secs(5), Ordering::SeqCst), Duration::from_secs(7));
278  /// assert_eq!(x.load(Ordering::SeqCst), Duration::from_secs(5));
279  /// ```
280  #[inline(always)]
281  pub fn fetch_min(&self, val: Duration, order: Ordering) -> Duration {
282    decode_duration(self.0.fetch_min(encode_duration(val), order))
283  }
284
285  /// Atomically stores the larger of the current value and `val`, returning
286  /// the previous value.
287  ///
288  /// `order` describes the memory ordering of the read-modify-write operation.
289  /// Using [`Acquire`](Ordering::Acquire) makes its store part relaxed, and
290  /// using [`Release`](Ordering::Release) makes its load part relaxed.
291  ///
292  /// # Examples
293  ///
294  /// ```rust
295  /// use atomic_time::AtomicDuration;
296  /// use std::{sync::atomic::Ordering, time::Duration};
297  ///
298  /// let x = AtomicDuration::new(Duration::from_secs(5));
299  /// assert_eq!(x.fetch_max(Duration::from_secs(7), Ordering::SeqCst), Duration::from_secs(5));
300  /// assert_eq!(x.load(Ordering::SeqCst), Duration::from_secs(7));
301  /// ```
302  #[inline(always)]
303  pub fn fetch_max(&self, val: Duration, order: Ordering) -> Duration {
304    decode_duration(self.0.fetch_max(encode_duration(val), order))
305  }
306
307  /// Adds `val` to the current value with saturation, returning the previous
308  /// value.
309  ///
310  /// This never overflows: values above [`Duration::MAX`] remain saturated at
311  /// `Duration::MAX`. `order` describes the successful update ordering.
312  ///
313  /// # Examples
314  ///
315  /// ```rust
316  /// use atomic_time::AtomicDuration;
317  /// use std::{sync::atomic::Ordering, time::Duration};
318  ///
319  /// let x = AtomicDuration::new(Duration::new(0, 999_999_999));
320  /// assert_eq!(x.fetch_saturating_add(Duration::from_nanos(1), Ordering::SeqCst), Duration::new(0, 999_999_999));
321  /// assert_eq!(x.load(Ordering::SeqCst), Duration::from_secs(1));
322  /// ```
323  #[inline(always)]
324  pub fn fetch_saturating_add(&self, val: Duration, order: Ordering) -> Duration {
325    self.update(order, Ordering::Relaxed, |old| old.saturating_add(val))
326  }
327
328  /// Subtracts `val` from the current value with saturation, returning the
329  /// previous value.
330  ///
331  /// This never underflows: values below [`Duration::ZERO`] remain saturated at
332  /// `Duration::ZERO`. `order` describes the successful update ordering.
333  ///
334  /// # Examples
335  ///
336  /// ```rust
337  /// use atomic_time::AtomicDuration;
338  /// use std::{sync::atomic::Ordering, time::Duration};
339  ///
340  /// let x = AtomicDuration::new(Duration::ZERO);
341  /// assert_eq!(x.fetch_saturating_sub(Duration::from_nanos(1), Ordering::SeqCst), Duration::ZERO);
342  /// assert_eq!(x.load(Ordering::SeqCst), Duration::ZERO);
343  /// ```
344  #[inline(always)]
345  pub fn fetch_saturating_sub(&self, val: Duration, order: Ordering) -> Duration {
346    self.update(order, Ordering::Relaxed, |old| old.saturating_sub(val))
347  }
348  /// Consumes the atomic and returns the contained value.
349  ///
350  /// This is safe because passing `self` by value guarantees that no other threads are
351  /// concurrently accessing the atomic data.
352  #[inline(always)]
353  pub fn into_inner(self) -> Duration {
354    decode_duration(self.0.into_inner())
355  }
356
357  /// Returns `true` if operations on values of this type are lock-free.
358  /// If the compiler or the platform doesn't support the necessary
359  /// atomic instructions, global locks for every potentially
360  /// concurrent atomic operation will be used.
361  ///
362  /// # Examples
363  /// ```
364  /// use atomic_time::AtomicDuration;
365  ///
366  /// let is_lock_free = AtomicDuration::is_lock_free();
367  /// ```
368  #[inline(always)]
369  pub fn is_lock_free() -> bool {
370    AtomicU128::is_lock_free()
371  }
372
373  /// Returns whether operations on values of this type are always lock-free.
374  ///
375  /// A `false` result does not preclude lock-free operations selected through
376  /// runtime CPU feature detection; use [`is_lock_free`](Self::is_lock_free)
377  /// to query the current target at runtime.
378  ///
379  /// # Examples
380  ///
381  /// ```rust
382  /// use atomic_time::AtomicDuration;
383  ///
384  /// const ALWAYS_LOCK_FREE: bool = AtomicDuration::is_always_lock_free();
385  /// let _ = ALWAYS_LOCK_FREE;
386  /// ```
387  #[inline(always)]
388  pub const fn is_always_lock_free() -> bool {
389    AtomicU128::is_always_lock_free()
390  }
391}
392
393/// Encodes a [`Duration`] into a [`u128`].
394#[inline(always)]
395pub const fn encode_duration(duration: Duration) -> u128 {
396  let seconds = duration.as_secs() as u128;
397  let nanos = duration.subsec_nanos() as u128;
398  (seconds << 32) + nanos
399}
400
401/// Decodes a [`u128`] into a [`Duration`].
402///
403/// Accepts non-canonical input without panicking. The encoding
404/// produced by [`encode_duration`] stores 64 bits of seconds in bits
405/// 32..=95 and at most 30 bits of nanoseconds (the valid range
406/// `0..1_000_000_000`) in bits 0..=31. If the decoded bits carry a
407/// nanosecond count of 10⁹ or more — which `encode_duration` never
408/// produces, but which can appear when the encoded value comes from
409/// corrupted storage or untrusted input — the extra whole seconds are
410/// folded into the seconds field; if that push past `u64::MAX`, the
411/// result saturates at [`Duration::MAX`].
412///
413/// This means `decode_duration(u128::MAX)` yields a saturated
414/// `Duration` rather than panicking as the previous implementation
415/// did.
416#[inline(always)]
417pub const fn decode_duration(encoded: u128) -> Duration {
418  let seconds = (encoded >> 32) as u64;
419  let raw_nanos = (encoded & 0xFFFFFFFF) as u32;
420  // Normalize out-of-range nanoseconds before calling `Duration::new`
421  // — the latter panics if the carry from nanos overflows the
422  // seconds field.
423  let extra_secs = (raw_nanos / 1_000_000_000) as u64;
424  let nanos = raw_nanos % 1_000_000_000;
425  match seconds.checked_add(extra_secs) {
426    Some(secs) => Duration::new(secs, nanos),
427    None => Duration::new(u64::MAX, 999_999_999),
428  }
429}
430
431#[cfg(feature = "serde")]
432const _: () = {
433  use serde::{Deserialize, Serialize};
434
435  impl Serialize for AtomicDuration {
436    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
437      self.load(Ordering::SeqCst).serialize(serializer)
438    }
439  }
440
441  impl<'de> Deserialize<'de> for AtomicDuration {
442    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
443      Ok(Self::new(Duration::deserialize(deserializer)?))
444    }
445  }
446};
447
448#[cfg(test)]
449mod tests {
450  use super::*;
451
452  #[test]
453  fn test_atomic_duration_new() {
454    let duration = Duration::from_secs(5);
455    let atomic_duration = AtomicDuration::new(duration);
456    assert_eq!(atomic_duration.load(Ordering::SeqCst), duration);
457  }
458
459  #[test]
460  fn test_atomic_duration_load() {
461    let duration = Duration::new(10, 10);
462    let atomic_duration = AtomicDuration::new(duration);
463    assert_eq!(atomic_duration.load(Ordering::SeqCst), duration);
464  }
465
466  #[test]
467  fn test_atomic_duration_store() {
468    let initial_duration = Duration::from_secs(3);
469    let new_duration = Duration::from_secs(7);
470    let atomic_duration = AtomicDuration::new(initial_duration);
471    atomic_duration.store(new_duration, Ordering::SeqCst);
472    assert_eq!(atomic_duration.load(Ordering::SeqCst), new_duration);
473  }
474
475  #[test]
476  fn test_atomic_duration_swap() {
477    let initial_duration = Duration::from_secs(2);
478    let new_duration = Duration::from_secs(8);
479    let atomic_duration = AtomicDuration::new(initial_duration);
480    let prev_duration = atomic_duration.swap(new_duration, Ordering::SeqCst);
481    assert_eq!(prev_duration, initial_duration);
482    assert_eq!(atomic_duration.load(Ordering::SeqCst), new_duration);
483  }
484
485  #[test]
486  fn test_atomic_duration_compare_exchange_weak() {
487    let initial_duration = Duration::from_secs(4);
488    let atomic_duration = AtomicDuration::new(initial_duration);
489
490    // Successful exchange
491    let mut result;
492    loop {
493      result = atomic_duration.compare_exchange_weak(
494        initial_duration,
495        Duration::from_secs(6),
496        Ordering::SeqCst,
497        Ordering::SeqCst,
498      );
499
500      if result.is_ok() || result.unwrap_err() != initial_duration {
501        // Break if successfully updated or if the current value is no longer initial_duration.
502        break;
503      }
504    }
505
506    assert!(result.is_ok());
507    assert_eq!(result.unwrap(), initial_duration);
508    assert_eq!(
509      atomic_duration.load(Ordering::SeqCst),
510      Duration::from_secs(6)
511    );
512
513    // Failed exchange
514    // Here, we expect this to fail as the current value is no longer `initial_duration`.
515    let result = atomic_duration.compare_exchange_weak(
516      initial_duration,
517      Duration::from_secs(7),
518      Ordering::SeqCst,
519      Ordering::SeqCst,
520    );
521
522    assert!(result.is_err());
523    // The error should be the current value, which is now Duration::from_secs(6).
524    assert_eq!(result.unwrap_err(), Duration::from_secs(6));
525  }
526
527  #[test]
528  fn test_atomic_duration_compare_exchange() {
529    let initial_duration = Duration::from_secs(1);
530    let atomic_duration = AtomicDuration::new(initial_duration);
531
532    // Successful exchange
533    let result = atomic_duration.compare_exchange(
534      initial_duration,
535      Duration::from_secs(5),
536      Ordering::SeqCst,
537      Ordering::SeqCst,
538    );
539    assert!(result.is_ok());
540    assert_eq!(result.unwrap(), initial_duration);
541    assert_eq!(
542      atomic_duration.load(Ordering::SeqCst),
543      Duration::from_secs(5)
544    );
545
546    // Failed exchange
547    let result = atomic_duration.compare_exchange(
548      initial_duration,
549      Duration::from_secs(6),
550      Ordering::SeqCst,
551      Ordering::SeqCst,
552    );
553    assert!(result.is_err());
554    assert_eq!(result.unwrap_err(), Duration::from_secs(5));
555  }
556
557  #[test]
558  fn test_atomic_duration_fetch_update() {
559    let initial_duration = Duration::from_secs(4);
560    let atomic_duration = AtomicDuration::new(initial_duration);
561
562    let result = atomic_duration.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |d| {
563      Some(d + Duration::from_secs(2))
564    });
565    assert_eq!(result, Ok(initial_duration));
566    assert_eq!(
567      atomic_duration.load(Ordering::SeqCst),
568      Duration::from_secs(6)
569    );
570  }
571
572  #[test]
573  fn test_atomic_duration_try_update() {
574    let initial = Duration::from_secs(4);
575    let atomic_duration = AtomicDuration::new(initial);
576
577    assert_eq!(
578      atomic_duration.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None),
579      Err(initial)
580    );
581    assert_eq!(
582      atomic_duration.try_update(Ordering::SeqCst, Ordering::SeqCst, |duration| {
583        Some(duration + Duration::from_secs(2))
584      }),
585      Ok(initial)
586    );
587    assert_eq!(
588      atomic_duration.load(Ordering::SeqCst),
589      Duration::from_secs(6)
590    );
591  }
592
593  #[test]
594  fn test_atomic_duration_update_returns_previous_value() {
595    let initial = Duration::from_secs(4);
596    let atomic_duration = AtomicDuration::new(initial);
597
598    assert_eq!(
599      atomic_duration.update(Ordering::SeqCst, Ordering::SeqCst, |duration| {
600        duration + Duration::from_secs(2)
601      }),
602      initial
603    );
604    assert_eq!(
605      atomic_duration.load(Ordering::SeqCst),
606      Duration::from_secs(6)
607    );
608  }
609
610  #[test]
611  fn test_atomic_duration_fetch_min_and_max() {
612    let low = Duration::from_secs(3);
613    let middle = Duration::from_secs(5);
614    let high = Duration::from_secs(7);
615    let atomic_duration = AtomicDuration::new(middle);
616
617    assert_eq!(atomic_duration.fetch_min(high, Ordering::SeqCst), middle);
618    assert_eq!(atomic_duration.load(Ordering::SeqCst), middle);
619    assert_eq!(atomic_duration.fetch_min(middle, Ordering::SeqCst), middle);
620    assert_eq!(atomic_duration.load(Ordering::SeqCst), middle);
621    assert_eq!(atomic_duration.fetch_min(low, Ordering::SeqCst), middle);
622    assert_eq!(atomic_duration.load(Ordering::SeqCst), low);
623
624    atomic_duration.store(middle, Ordering::SeqCst);
625    assert_eq!(atomic_duration.fetch_max(low, Ordering::SeqCst), middle);
626    assert_eq!(atomic_duration.load(Ordering::SeqCst), middle);
627    assert_eq!(atomic_duration.fetch_max(middle, Ordering::SeqCst), middle);
628    assert_eq!(atomic_duration.load(Ordering::SeqCst), middle);
629    assert_eq!(atomic_duration.fetch_max(high, Ordering::SeqCst), middle);
630    assert_eq!(atomic_duration.load(Ordering::SeqCst), high);
631  }
632
633  #[test]
634  fn test_atomic_duration_fetch_saturating_arithmetic() {
635    let atomic_duration = AtomicDuration::new(Duration::new(0, 999_999_999));
636    assert_eq!(
637      atomic_duration.fetch_saturating_add(Duration::from_nanos(1), Ordering::SeqCst),
638      Duration::new(0, 999_999_999)
639    );
640    assert_eq!(
641      atomic_duration.load(Ordering::SeqCst),
642      Duration::from_secs(1)
643    );
644
645    atomic_duration.store(Duration::MAX, Ordering::SeqCst);
646    assert_eq!(
647      atomic_duration.fetch_saturating_add(Duration::from_nanos(1), Ordering::SeqCst),
648      Duration::MAX
649    );
650    assert_eq!(atomic_duration.load(Ordering::SeqCst), Duration::MAX);
651
652    atomic_duration.store(Duration::ZERO, Ordering::SeqCst);
653    assert_eq!(
654      atomic_duration.fetch_saturating_sub(Duration::from_nanos(1), Ordering::SeqCst),
655      Duration::ZERO
656    );
657    assert_eq!(atomic_duration.load(Ordering::SeqCst), Duration::ZERO);
658  }
659
660  #[test]
661  fn test_atomic_duration_always_lock_free_implies_lock_free() {
662    assert!(!AtomicDuration::is_always_lock_free() || AtomicDuration::is_lock_free());
663  }
664
665  #[test]
666  fn test_atomic_duration_into_inner() {
667    let duration = Duration::from_secs(3);
668    let atomic_duration = AtomicDuration::new(duration);
669    assert_eq!(atomic_duration.into_inner(), duration);
670  }
671
672  #[test]
673  #[cfg(feature = "std")]
674  fn test_atomic_duration_thread_safety() {
675    use std::sync::Arc;
676    use std::thread;
677
678    let atomic_duration = Arc::new(AtomicDuration::new(Duration::from_secs(0)));
679    let mut handles = vec![];
680
681    // Spawn multiple threads to increment the duration
682    for _ in 0..10 {
683      let atomic_clone = Arc::clone(&atomic_duration);
684      let handle = thread::spawn(move || {
685        for _ in 0..100 {
686          loop {
687            let current = atomic_clone.load(Ordering::SeqCst);
688            let new = current + Duration::from_millis(1);
689            match atomic_clone.compare_exchange_weak(
690              current,
691              new,
692              Ordering::SeqCst,
693              Ordering::SeqCst,
694            ) {
695              Ok(_) => break,     // Successfully updated
696              Err(_) => continue, // Spurious failure, try again
697            }
698          }
699        }
700      });
701      handles.push(handle);
702    }
703
704    // Wait for all threads to complete
705    for handle in handles {
706      handle.join().unwrap();
707    }
708
709    // Verify the final value
710    let expected_duration = Duration::from_millis(10 * 100);
711    assert_eq!(atomic_duration.load(Ordering::SeqCst), expected_duration);
712  }
713
714  #[test]
715  #[cfg(feature = "std")]
716  fn test_atomic_duration_update_is_exact_under_contention() {
717    use std::sync::Arc;
718    use std::thread;
719
720    let atomic_duration = Arc::new(AtomicDuration::new(Duration::ZERO));
721    let mut handles = vec![];
722
723    for _ in 0..4 {
724      let atomic_clone = Arc::clone(&atomic_duration);
725      handles.push(thread::spawn(move || {
726        for _ in 0..100 {
727          atomic_clone.update(Ordering::SeqCst, Ordering::SeqCst, |duration| {
728            duration.saturating_add(Duration::from_nanos(1))
729          });
730        }
731      }));
732    }
733
734    for handle in handles {
735      handle.join().unwrap();
736    }
737
738    let expected = Duration::from_nanos(400);
739    assert_eq!(atomic_duration.load(Ordering::SeqCst), expected);
740    assert_eq!(
741      atomic_duration.fetch_saturating_add(Duration::MAX, Ordering::SeqCst),
742      expected
743    );
744    assert_eq!(atomic_duration.load(Ordering::SeqCst), Duration::MAX);
745  }
746
747  #[cfg(feature = "std")]
748  #[test]
749  fn test_atomic_duration_debug() {
750    let duration = Duration::new(1, 500_000_000);
751    let atomic_duration = AtomicDuration::new(duration);
752    let debug_str = format!("{:?}", atomic_duration);
753    assert!(debug_str.contains("AtomicDuration"));
754  }
755
756  #[test]
757  fn test_atomic_duration_default() {
758    let atomic_duration = AtomicDuration::default();
759    assert_eq!(atomic_duration.load(Ordering::SeqCst), Duration::ZERO);
760  }
761
762  #[test]
763  fn test_atomic_duration_from() {
764    let duration = Duration::from_secs(42);
765    let atomic_duration = AtomicDuration::from(duration);
766    assert_eq!(atomic_duration.load(Ordering::SeqCst), duration);
767  }
768
769  #[cfg(feature = "serde")]
770  #[test]
771  fn test_atomic_duration_serde() {
772    let atomic = AtomicDuration::new(Duration::from_secs(5));
773    let serialized = serde_json::to_string(&atomic).unwrap();
774    let deserialized: AtomicDuration = serde_json::from_str(&serialized).unwrap();
775    assert_eq!(deserialized.load(Ordering::SeqCst), Duration::from_secs(5));
776  }
777
778  #[test]
779  fn decode_duration_roundtrip() {
780    let cases = [
781      Duration::ZERO,
782      Duration::from_secs(1),
783      Duration::new(123_456_789, 999_999_999),
784      Duration::new(u64::MAX, 999_999_999),
785    ];
786    for d in cases {
787      assert_eq!(decode_duration(encode_duration(d)), d);
788    }
789  }
790
791  #[test]
792  fn decode_duration_saturates_on_non_canonical_input() {
793    // u128::MAX has nanos = u32::MAX (> 1e9) and seconds = u64::MAX,
794    // so the carry from normalising nanos overflows u64 — the old
795    // implementation panicked here.
796    let max = decode_duration(u128::MAX);
797    assert_eq!(max, Duration::new(u64::MAX, 999_999_999));
798
799    // A value with just out-of-range nanos (but within seconds budget):
800    // encode(0 secs, 2_000_000_000 nanos) — hand-crafted, not produced
801    // by encode_duration.
802    let d = decode_duration(2_000_000_000u128);
803    assert_eq!(d, Duration::new(2, 0));
804  }
805}