1use crate::AtomicU128;
2use core::{sync::atomic::Ordering, time::Duration};
3
4#[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 #[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 #[inline(always)]
30 pub const fn new(duration: Duration) -> Self {
31 Self(AtomicU128::new(encode_duration(duration)))
32 }
33 #[inline(always)]
40 pub fn load(&self, ordering: Ordering) -> Duration {
41 decode_duration(self.0.load(ordering))
42 }
43 #[inline(always)]
52 pub fn store(&self, val: Duration, ordering: Ordering) {
53 self.0.store(encode_duration(val), ordering)
54 }
55 #[inline(always)]
60 pub fn swap(&self, val: Duration, ordering: Ordering) -> Duration {
61 decode_duration(self.0.swap(encode_duration(val), ordering))
62 }
63 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[inline(always)]
353 pub fn into_inner(self) -> Duration {
354 decode_duration(self.0.into_inner())
355 }
356
357 #[inline(always)]
369 pub fn is_lock_free() -> bool {
370 AtomicU128::is_lock_free()
371 }
372
373 #[inline(always)]
388 pub const fn is_always_lock_free() -> bool {
389 AtomicU128::is_always_lock_free()
390 }
391}
392
393#[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#[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 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 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;
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 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 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 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 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 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, Err(_) => continue, }
698 }
699 }
700 });
701 handles.push(handle);
702 }
703
704 for handle in handles {
706 handle.join().unwrap();
707 }
708
709 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 let max = decode_duration(u128::MAX);
797 assert_eq!(max, Duration::new(u64::MAX, 999_999_999));
798
799 let d = decode_duration(2_000_000_000u128);
803 assert_eq!(d, Duration::new(2, 0));
804 }
805}