1use core::sync::atomic::Ordering;
2use std::time::SystemTime;
3
4use crate::AtomicOptionDuration;
5
6#[repr(transparent)]
10pub struct AtomicOptionSystemTime(AtomicOptionDuration);
11
12impl core::fmt::Debug for AtomicOptionSystemTime {
13 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
14 f.debug_tuple("AtomicOptionSystemTime")
15 .field(&self.load(Ordering::SeqCst))
16 .finish()
17 }
18}
19impl Default for AtomicOptionSystemTime {
20 #[inline(always)]
22 fn default() -> Self {
23 Self::none()
24 }
25}
26impl From<Option<SystemTime>> for AtomicOptionSystemTime {
27 #[inline(always)]
31 fn from(system_time: Option<SystemTime>) -> Self {
32 Self::new(system_time)
33 }
34}
35
36impl AtomicOptionSystemTime {
37 #[inline(always)]
48 pub const fn none() -> Self {
49 Self(AtomicOptionDuration::new(None))
50 }
51
52 #[inline(always)]
61 pub fn now() -> Self {
62 Self::new(Some(SystemTime::now()))
63 }
64
65 #[inline(always)]
71 pub fn new(system_time: Option<SystemTime>) -> Self {
72 Self(AtomicOptionDuration::new(
73 system_time.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
74 ))
75 }
76
77 #[inline(always)]
79 pub fn load(&self, order: Ordering) -> Option<SystemTime> {
80 self.0.load(order).map(|val| SystemTime::UNIX_EPOCH + val)
81 }
82
83 #[inline(always)]
89 pub fn store(&self, system_time: Option<SystemTime>, order: Ordering) {
90 self.0.store(
91 system_time.map(|val| val.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
92 order,
93 )
94 }
95
96 #[inline(always)]
102 pub fn swap(&self, system_time: Option<SystemTime>, order: Ordering) -> Option<SystemTime> {
103 self
104 .0
105 .swap(
106 system_time.map(|val| val.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
107 order,
108 )
109 .map(|val| SystemTime::UNIX_EPOCH + val)
110 }
111
112 #[inline(always)]
119 pub fn compare_exchange(
120 &self,
121 current: Option<SystemTime>,
122 new: Option<SystemTime>,
123 success: Ordering,
124 failure: Ordering,
125 ) -> Result<Option<SystemTime>, Option<SystemTime>> {
126 match self.0.compare_exchange(
127 current.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
128 new.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
129 success,
130 failure,
131 ) {
132 Ok(duration) => Ok(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
133 Err(duration) => Err(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
134 }
135 }
136
137 #[inline(always)]
144 pub fn compare_exchange_weak(
145 &self,
146 current: Option<SystemTime>,
147 new: Option<SystemTime>,
148 success: Ordering,
149 failure: Ordering,
150 ) -> Result<Option<SystemTime>, Option<SystemTime>> {
151 match self.0.compare_exchange_weak(
152 current.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
153 new.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
154 success,
155 failure,
156 ) {
157 Ok(duration) => Ok(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
158 Err(duration) => Err(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
159 }
160 }
161
162 #[inline(always)]
195 pub fn try_update<F>(
196 &self,
197 set_order: Ordering,
198 fetch_order: Ordering,
199 mut f: F,
200 ) -> Result<Option<SystemTime>, Option<SystemTime>>
201 where
202 F: FnMut(Option<SystemTime>) -> Option<Option<SystemTime>>,
203 {
204 self
205 .0
206 .try_update(set_order, fetch_order, |duration| {
207 f(duration.map(|d| SystemTime::UNIX_EPOCH + d))
208 .map(|system_time| system_time.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()))
209 })
210 .map(|duration| duration.map(|d| SystemTime::UNIX_EPOCH + d))
211 .map_err(|duration| duration.map(|d| SystemTime::UNIX_EPOCH + d))
212 }
213
214 #[inline(always)]
254 pub fn fetch_update<F>(
255 &self,
256 set_order: Ordering,
257 fetch_order: Ordering,
258 f: F,
259 ) -> Result<Option<SystemTime>, Option<SystemTime>>
260 where
261 F: FnMut(Option<SystemTime>) -> Option<Option<SystemTime>>,
262 {
263 self.try_update(set_order, fetch_order, f)
264 }
265
266 #[inline(always)]
293 pub fn update<F>(
294 &self,
295 set_order: Ordering,
296 fetch_order: Ordering,
297 mut f: F,
298 ) -> Option<SystemTime>
299 where
300 F: FnMut(Option<SystemTime>) -> Option<SystemTime>,
301 {
302 self
303 .0
304 .update(set_order, fetch_order, |duration| {
305 f(duration.map(|d| SystemTime::UNIX_EPOCH + d))
306 .map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap())
307 })
308 .map(|d| SystemTime::UNIX_EPOCH + d)
309 }
310
311 #[inline(always)]
340 pub fn fetch_min(&self, val: Option<SystemTime>, order: Ordering) -> Option<SystemTime> {
341 self
342 .0
343 .fetch_min(
344 val.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
345 order,
346 )
347 .map(|d| SystemTime::UNIX_EPOCH + d)
348 }
349
350 #[inline(always)]
377 pub fn fetch_max(&self, val: Option<SystemTime>, order: Ordering) -> Option<SystemTime> {
378 self
379 .0
380 .fetch_max(
381 val.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
382 order,
383 )
384 .map(|d| SystemTime::UNIX_EPOCH + d)
385 }
386
387 #[inline(always)]
399 pub fn is_lock_free() -> bool {
400 AtomicOptionDuration::is_lock_free()
401 }
402
403 #[inline(always)]
418 pub const fn is_always_lock_free() -> bool {
419 AtomicOptionDuration::is_always_lock_free()
420 }
421
422 #[inline(always)]
427 pub fn into_inner(self) -> Option<SystemTime> {
428 self.0.into_inner().map(|d| SystemTime::UNIX_EPOCH + d)
429 }
430}
431
432#[cfg(feature = "serde")]
433const _: () = {
434 use serde::{Deserialize, Serialize};
435
436 impl Serialize for AtomicOptionSystemTime {
437 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
438 self.load(Ordering::SeqCst).serialize(serializer)
439 }
440 }
441
442 impl<'de> Deserialize<'de> for AtomicOptionSystemTime {
443 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
444 Ok(Self::new(Option::<SystemTime>::deserialize(deserializer)?))
445 }
446 }
447};
448
449#[cfg(test)]
450mod tests {
451 use super::*;
452 use std::time::Duration;
453
454 #[test]
455 fn test_atomic_option_system_time_now() {
456 let atomic_time = AtomicOptionSystemTime::now();
457 assert!(atomic_time.load(Ordering::SeqCst).is_some());
459 }
460
461 #[test]
462 fn test_atomic_option_system_time_none() {
463 let atomic_time = AtomicOptionSystemTime::none();
464 assert_eq!(atomic_time.load(Ordering::SeqCst), None);
465 }
466
467 #[test]
468 fn test_atomic_option_system_time_new_and_load() {
469 let now = SystemTime::now();
470 let atomic_time = AtomicOptionSystemTime::new(Some(now));
471 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(now));
472 }
473
474 #[test]
475 fn test_atomic_option_system_time_store_and_load() {
476 let now = SystemTime::now();
477 let after_one_sec = now + Duration::from_secs(1);
478 let atomic_time = AtomicOptionSystemTime::new(Some(now));
479 atomic_time.store(Some(after_one_sec), Ordering::SeqCst);
480 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
481 }
482
483 #[test]
484 fn test_atomic_option_system_time_swap() {
485 let now = SystemTime::now();
486 let after_one_sec = now + Duration::from_secs(1);
487 let atomic_time = AtomicOptionSystemTime::new(Some(now));
488 let prev_time = atomic_time.swap(Some(after_one_sec), Ordering::SeqCst);
489 assert_eq!(prev_time, Some(now));
490 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
491 }
492
493 #[test]
494 fn test_atomic_option_system_time_compare_exchange() {
495 let now = SystemTime::now();
496 let after_one_sec = now + Duration::from_secs(1);
497 let atomic_time = AtomicOptionSystemTime::new(Some(now));
498 let result = atomic_time.compare_exchange(
499 Some(now),
500 Some(after_one_sec),
501 Ordering::SeqCst,
502 Ordering::SeqCst,
503 );
504 assert!(result.is_ok());
505 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
506 }
507
508 #[test]
509 fn test_atomic_option_system_time_compare_exchange_weak() {
510 let now = SystemTime::now();
511 let after_one_sec = now + Duration::from_secs(1);
512 let atomic_time = AtomicOptionSystemTime::new(Some(now));
513
514 let mut result;
515 loop {
516 result = atomic_time.compare_exchange_weak(
517 Some(now),
518 Some(after_one_sec),
519 Ordering::SeqCst,
520 Ordering::SeqCst,
521 );
522 if result.is_ok() {
523 break;
524 }
525 }
526 assert!(result.is_ok());
527 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
528 }
529
530 #[test]
531 fn test_atomic_option_system_time_fetch_update() {
532 let now = SystemTime::now();
533 let atomic_time = AtomicOptionSystemTime::new(Some(now));
534
535 let result = atomic_time.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
536 Some(prev.map(|val| val + Duration::from_secs(1)))
537 });
538 assert!(result.is_ok());
539 assert_eq!(result.unwrap(), Some(now));
540 assert_eq!(
541 atomic_time.load(Ordering::SeqCst),
542 Some(now + Duration::from_secs(1))
543 );
544 }
545
546 #[test]
547 fn test_atomic_option_system_time_try_update() {
548 let start = SystemTime::UNIX_EPOCH + Duration::from_secs(10);
549 let atomic_time = AtomicOptionSystemTime::new(Some(start));
550
551 assert_eq!(
552 atomic_time.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None),
553 Err(Some(start))
554 );
555 assert_eq!(
556 atomic_time.try_update(Ordering::SeqCst, Ordering::SeqCst, |current| {
557 Some(current.map(|time| time + Duration::from_secs(2)))
558 }),
559 Ok(Some(start))
560 );
561 assert_eq!(
562 atomic_time.load(Ordering::SeqCst),
563 Some(start + Duration::from_secs(2))
564 );
565 }
566
567 #[test]
568 fn test_atomic_option_system_time_update_returns_previous_value() {
569 let start = SystemTime::UNIX_EPOCH + Duration::from_secs(10);
570 let atomic_time = AtomicOptionSystemTime::new(Some(start));
571
572 assert_eq!(
573 atomic_time.update(Ordering::SeqCst, Ordering::SeqCst, |current| {
574 current.map(|time| time + Duration::from_secs(2))
575 }),
576 Some(start)
577 );
578 assert_eq!(
579 atomic_time.load(Ordering::SeqCst),
580 Some(start + Duration::from_secs(2))
581 );
582 }
583
584 #[test]
585 fn test_atomic_option_system_time_fetch_min_and_max() {
586 let low = SystemTime::UNIX_EPOCH + Duration::from_secs(10);
587 let middle = low + Duration::from_secs(5);
588 let high = middle + Duration::from_secs(5);
589 let atomic_time = AtomicOptionSystemTime::new(Some(middle));
590
591 assert_eq!(
592 atomic_time.fetch_min(Some(high), Ordering::SeqCst),
593 Some(middle)
594 );
595 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(middle));
596 assert_eq!(
597 atomic_time.fetch_min(Some(middle), Ordering::SeqCst),
598 Some(middle)
599 );
600 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(middle));
601 assert_eq!(
602 atomic_time.fetch_min(Some(low), Ordering::SeqCst),
603 Some(middle)
604 );
605 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(low));
606
607 atomic_time.store(Some(middle), Ordering::SeqCst);
608 assert_eq!(atomic_time.fetch_max(None, Ordering::SeqCst), Some(middle));
609 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(middle));
610 assert_eq!(
611 atomic_time.fetch_max(Some(middle), Ordering::SeqCst),
612 Some(middle)
613 );
614 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(middle));
615 assert_eq!(
616 atomic_time.fetch_max(Some(high), Ordering::SeqCst),
617 Some(middle)
618 );
619 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(high));
620
621 atomic_time.store(None, Ordering::SeqCst);
622 assert_eq!(atomic_time.fetch_min(None, Ordering::SeqCst), None);
623 assert_eq!(atomic_time.load(Ordering::SeqCst), None);
624 assert_eq!(atomic_time.fetch_max(None, Ordering::SeqCst), None);
625 assert_eq!(atomic_time.load(Ordering::SeqCst), None);
626 assert_eq!(atomic_time.fetch_max(Some(low), Ordering::SeqCst), None);
627 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(low));
628 }
629
630 #[test]
631 fn test_atomic_option_system_time_always_lock_free_implies_lock_free() {
632 assert!(
633 !AtomicOptionSystemTime::is_always_lock_free() || AtomicOptionSystemTime::is_lock_free()
634 );
635 }
636
637 #[test]
638 #[should_panic]
639 fn test_atomic_option_system_time_fetch_min_before_epoch_panics() {
640 let atomic_time = AtomicOptionSystemTime::none();
641 atomic_time.fetch_min(
642 Some(SystemTime::UNIX_EPOCH - Duration::from_secs(1)),
643 Ordering::SeqCst,
644 );
645 }
646
647 #[test]
648 fn test_atomic_option_system_time_thread_safety() {
649 use std::sync::Arc;
650 use std::thread;
651
652 let start = SystemTime::now();
657 let atomic_time = Arc::new(AtomicOptionSystemTime::new(Some(start)));
658 let mut handles = vec![];
659
660 for _ in 0..4 {
661 let atomic_clone = Arc::clone(&atomic_time);
662 let handle = thread::spawn(move || {
663 atomic_clone
664 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |current| {
665 current.map(|t| Some(t + Duration::from_secs(1)))
666 })
667 .expect("atomic is always Some in this test");
668 });
669 handles.push(handle);
670 }
671
672 for handle in handles {
673 handle.join().unwrap();
674 }
675
676 assert_eq!(
678 atomic_time.load(Ordering::SeqCst),
679 Some(start + Duration::from_secs(4))
680 );
681 }
682
683 #[test]
684 fn test_atomic_option_system_time_debug() {
685 let atomic_time = AtomicOptionSystemTime::now();
686 let debug_str = format!("{:?}", atomic_time);
687 assert!(debug_str.contains("AtomicOptionSystemTime"));
688 }
689
690 #[test]
691 fn test_atomic_option_system_time_default() {
692 let atomic_time = AtomicOptionSystemTime::default();
693 assert_eq!(atomic_time.load(Ordering::SeqCst), None);
694 }
695
696 #[test]
697 fn test_atomic_option_system_time_from() {
698 let now = Some(SystemTime::now());
699 let atomic_time = AtomicOptionSystemTime::from(now);
700 assert_eq!(atomic_time.load(Ordering::SeqCst), now);
701 }
702
703 #[test]
704 fn test_atomic_option_system_time_from_none() {
705 let atomic_time = AtomicOptionSystemTime::from(None);
706 assert_eq!(atomic_time.load(Ordering::SeqCst), None);
707 }
708
709 #[test]
710 fn test_atomic_option_system_time_into_inner() {
711 let now = Some(SystemTime::now());
712 let atomic_time = AtomicOptionSystemTime::new(now);
713 assert_eq!(atomic_time.into_inner(), now);
714 }
715
716 #[test]
717 fn test_atomic_option_system_time_into_inner_none() {
718 let atomic_time = AtomicOptionSystemTime::none();
719 assert_eq!(atomic_time.into_inner(), None);
720 }
721
722 #[test]
723 fn test_atomic_option_system_time_compare_exchange_failure() {
724 let now = Some(SystemTime::now());
725 let other = now.map(|t| t + Duration::from_secs(5));
726 let atomic_time = AtomicOptionSystemTime::new(now);
727 let result = atomic_time.compare_exchange(other, other, Ordering::SeqCst, Ordering::SeqCst);
728 assert!(result.is_err());
729 assert_eq!(result.unwrap_err(), now);
730 }
731
732 #[test]
733 fn test_atomic_option_system_time_compare_exchange_weak_failure() {
734 let now = Some(SystemTime::now());
735 let other = now.map(|t| t + Duration::from_secs(5));
736 let atomic_time = AtomicOptionSystemTime::new(now);
737 let result =
738 atomic_time.compare_exchange_weak(other, other, Ordering::SeqCst, Ordering::SeqCst);
739 assert!(result.is_err());
740 }
741
742 #[test]
743 fn test_atomic_option_system_time_fetch_update_failure() {
744 let now = Some(SystemTime::now());
745 let atomic_time = AtomicOptionSystemTime::new(now);
746 let result = atomic_time.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None);
747 assert!(result.is_err());
748 assert_eq!(result.unwrap_err(), now);
749 }
750
751 #[cfg(feature = "serde")]
752 #[test]
753 fn test_atomic_option_system_time_serde() {
754 let now = SystemTime::now();
755 let atomic = AtomicOptionSystemTime::new(Some(now));
756 let serialized = serde_json::to_string(&atomic).unwrap();
757 let deserialized: AtomicOptionSystemTime = serde_json::from_str(&serialized).unwrap();
758 assert_eq!(deserialized.load(Ordering::SeqCst), Some(now));
759 }
760}