1use core::sync::atomic::Ordering;
2use std::time::SystemTime;
3
4use crate::AtomicDuration;
5
6#[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 #[inline(always)]
25 fn from(system_time: SystemTime) -> Self {
26 Self::new(system_time)
27 }
28}
29
30impl AtomicSystemTime {
31 #[inline(always)]
40 pub fn now() -> Self {
41 Self::new(SystemTime::now())
42 }
43
44 #[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 #[inline(always)]
58 pub fn load(&self, order: Ordering) -> SystemTime {
59 SystemTime::UNIX_EPOCH + self.0.load(order)
60 }
61
62 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[inline(always)]
354 pub fn is_lock_free() -> bool {
355 AtomicDuration::is_lock_free()
356 }
357
358 #[inline(always)]
373 pub const fn is_always_lock_free() -> bool {
374 AtomicDuration::is_always_lock_free()
375 }
376
377 #[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 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 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 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 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 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 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 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}