1use std::time::Instant;
2
3use super::*;
4
5#[repr(transparent)]
20pub struct AtomicInstant(AtomicDuration);
21
22impl core::fmt::Debug for AtomicInstant {
23 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
24 f.debug_tuple("AtomicInstant")
25 .field(&self.load(Ordering::SeqCst))
26 .finish()
27 }
28}
29impl From<Instant> for AtomicInstant {
30 #[inline(always)]
31 fn from(instant: Instant) -> Self {
32 Self::new(instant)
33 }
34}
35impl AtomicInstant {
36 #[inline(always)]
45 pub fn now() -> Self {
46 Self::new(Instant::now())
47 }
48
49 #[inline(always)]
51 pub fn new(instant: Instant) -> Self {
52 Self(AtomicDuration::new(encode_instant_to_duration(instant)))
53 }
54
55 #[inline(always)]
57 pub fn load(&self, order: Ordering) -> Instant {
58 decode_instant_from_duration(self.0.load(order))
59 }
60
61 #[inline(always)]
63 pub fn store(&self, instant: Instant, order: Ordering) {
64 self.0.store(encode_instant_to_duration(instant), order)
65 }
66
67 #[inline(always)]
69 pub fn swap(&self, instant: Instant, order: Ordering) -> Instant {
70 decode_instant_from_duration(self.0.swap(encode_instant_to_duration(instant), order))
71 }
72
73 #[inline(always)]
76 pub fn compare_exchange(
77 &self,
78 current: Instant,
79 new: Instant,
80 success: Ordering,
81 failure: Ordering,
82 ) -> Result<Instant, Instant> {
83 match self.0.compare_exchange(
84 encode_instant_to_duration(current),
85 encode_instant_to_duration(new),
86 success,
87 failure,
88 ) {
89 Ok(duration) => Ok(decode_instant_from_duration(duration)),
90 Err(duration) => Err(decode_instant_from_duration(duration)),
91 }
92 }
93
94 #[inline(always)]
97 pub fn compare_exchange_weak(
98 &self,
99 current: Instant,
100 new: Instant,
101 success: Ordering,
102 failure: Ordering,
103 ) -> Result<Instant, Instant> {
104 match self.0.compare_exchange_weak(
105 encode_instant_to_duration(current),
106 encode_instant_to_duration(new),
107 success,
108 failure,
109 ) {
110 Ok(duration) => Ok(decode_instant_from_duration(duration)),
111 Err(duration) => Err(decode_instant_from_duration(duration)),
112 }
113 }
114
115 #[inline(always)]
140 pub fn try_update<F>(
141 &self,
142 set_order: Ordering,
143 fetch_order: Ordering,
144 mut f: F,
145 ) -> Result<Instant, Instant>
146 where
147 F: FnMut(Instant) -> Option<Instant>,
148 {
149 self
150 .0
151 .try_update(set_order, fetch_order, |duration| {
152 f(decode_instant_from_duration(duration)).map(encode_instant_to_duration)
153 })
154 .map(decode_instant_from_duration)
155 .map_err(decode_instant_from_duration)
156 }
157
158 #[inline(always)]
193 pub fn fetch_update<F>(
194 &self,
195 set_order: Ordering,
196 fetch_order: Ordering,
197 f: F,
198 ) -> Result<Instant, Instant>
199 where
200 F: FnMut(Instant) -> Option<Instant>,
201 {
202 self.try_update(set_order, fetch_order, f)
203 }
204
205 #[inline(always)]
225 pub fn update<F>(&self, set_order: Ordering, fetch_order: Ordering, mut f: F) -> Instant
226 where
227 F: FnMut(Instant) -> Instant,
228 {
229 decode_instant_from_duration(self.0.update(set_order, fetch_order, |duration| {
230 encode_instant_to_duration(f(decode_instant_from_duration(duration)))
231 }))
232 }
233
234 #[inline(always)]
260 pub fn fetch_min(&self, val: Instant, order: Ordering) -> Instant {
261 decode_instant_from_duration(self.0.fetch_min(encode_instant_to_duration(val), order))
262 }
263
264 #[inline(always)]
290 pub fn fetch_max(&self, val: Instant, order: Ordering) -> Instant {
291 decode_instant_from_duration(self.0.fetch_max(encode_instant_to_duration(val), order))
292 }
293
294 #[inline(always)]
306 pub fn is_lock_free() -> bool {
307 AtomicU128::is_lock_free()
308 }
309
310 #[inline(always)]
325 pub const fn is_always_lock_free() -> bool {
326 AtomicDuration::is_always_lock_free()
327 }
328
329 #[inline(always)]
334 pub fn into_inner(self) -> Instant {
335 decode_instant_from_duration(self.0.into_inner())
336 }
337}
338
339#[cfg(feature = "serde")]
340const _: () = {
341 use core::time::Duration;
342 use serde::{Deserialize, Serialize};
343
344 impl Serialize for AtomicInstant {
345 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
346 self.0.load(Ordering::SeqCst).serialize(serializer)
347 }
348 }
349
350 impl<'de> Deserialize<'de> for AtomicInstant {
351 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
352 Ok(Self::new(decode_instant_from_duration(
353 Duration::deserialize(deserializer)?,
354 )))
355 }
356 }
357};
358
359#[cfg(test)]
360mod tests {
361 use super::*;
362 use std::time::Duration;
363
364 #[test]
365 fn test_atomic_instant_now() {
366 let atomic_instant = AtomicInstant::now();
367 let now = Instant::now();
369 let loaded_instant = atomic_instant.load(Ordering::SeqCst);
370 assert!(loaded_instant <= now);
371 assert!(loaded_instant >= now - Duration::from_secs(1));
372 }
373
374 #[test]
375 fn test_atomic_instant_new_and_load() {
376 let now = Instant::now();
377 let atomic_instant = AtomicInstant::new(now);
378 assert_eq!(atomic_instant.load(Ordering::SeqCst), now);
379 }
380
381 #[test]
382 fn test_atomic_instant_store_and_load() {
383 let now = Instant::now();
384 let after_one_sec = now + Duration::from_secs(1);
385 let atomic_instant = AtomicInstant::new(now);
386 atomic_instant.store(after_one_sec, Ordering::SeqCst);
387 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
388 }
389
390 #[test]
391 fn test_atomic_instant_swap() {
392 let now = Instant::now();
393 let after_one_sec = now + Duration::from_secs(1);
394 let atomic_instant = AtomicInstant::new(now);
395 let prev_instant = atomic_instant.swap(after_one_sec, Ordering::SeqCst);
396 assert_eq!(prev_instant, now);
397 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
398 }
399
400 #[test]
401 fn test_atomic_instant_compare_exchange() {
402 let now = Instant::now();
403 let after_one_sec = now + Duration::from_secs(1);
404 let atomic_instant = AtomicInstant::new(now);
405 let result =
406 atomic_instant.compare_exchange(now, after_one_sec, Ordering::SeqCst, Ordering::SeqCst);
407 assert!(result.is_ok());
408 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
409 }
410
411 #[test]
412 fn test_atomic_instant_compare_exchange_weak() {
413 let now = Instant::now();
414 let after_one_sec = now + Duration::from_secs(1);
415 let atomic_instant = AtomicInstant::new(now);
416
417 let mut result;
418 loop {
419 result = atomic_instant.compare_exchange_weak(
420 now,
421 after_one_sec,
422 Ordering::SeqCst,
423 Ordering::SeqCst,
424 );
425 if result.is_ok() {
426 break;
427 }
428 }
429 assert!(result.is_ok());
430 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
431 }
432
433 #[test]
434 fn test_atomic_instant_fetch_update() {
435 let now = Instant::now();
436 let atomic_instant = AtomicInstant::new(now);
437
438 let result = atomic_instant.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
439 Some(prev + Duration::from_secs(1))
440 });
441 assert!(result.is_ok());
442 assert_eq!(result.unwrap(), now);
443 assert_eq!(
444 atomic_instant.load(Ordering::SeqCst),
445 now + Duration::from_secs(1)
446 );
447 }
448
449 #[test]
450 fn test_atomic_instant_try_update() {
451 let start = Instant::now();
452 let atomic_instant = AtomicInstant::new(start);
453
454 assert_eq!(
455 atomic_instant.try_update(Ordering::SeqCst, Ordering::SeqCst, |_| None),
456 Err(start)
457 );
458 assert_eq!(
459 atomic_instant.try_update(Ordering::SeqCst, Ordering::SeqCst, |current| {
460 Some(current + Duration::from_secs(2))
461 }),
462 Ok(start)
463 );
464 assert_eq!(
465 atomic_instant.load(Ordering::SeqCst),
466 start + Duration::from_secs(2)
467 );
468 }
469
470 #[test]
471 fn test_atomic_instant_update_returns_previous_value() {
472 let start = Instant::now();
473 let atomic_instant = AtomicInstant::new(start);
474
475 assert_eq!(
476 atomic_instant.update(Ordering::SeqCst, Ordering::SeqCst, |current| {
477 current + Duration::from_secs(2)
478 }),
479 start
480 );
481 assert_eq!(
482 atomic_instant.load(Ordering::SeqCst),
483 start + Duration::from_secs(2)
484 );
485 }
486
487 #[test]
488 fn test_atomic_instant_fetch_min_and_max() {
489 let middle = Instant::now();
490 let low = middle.checked_sub(Duration::from_secs(2)).unwrap();
491 let high = middle.checked_add(Duration::from_secs(2)).unwrap();
492 let atomic_instant = AtomicInstant::new(middle);
493
494 assert_eq!(atomic_instant.fetch_min(high, Ordering::SeqCst), middle);
495 assert_eq!(atomic_instant.load(Ordering::SeqCst), middle);
496 assert_eq!(atomic_instant.fetch_min(middle, Ordering::SeqCst), middle);
497 assert_eq!(atomic_instant.load(Ordering::SeqCst), middle);
498 assert_eq!(atomic_instant.fetch_min(low, Ordering::SeqCst), middle);
499 assert_eq!(atomic_instant.load(Ordering::SeqCst), low);
500
501 atomic_instant.store(middle, Ordering::SeqCst);
502 assert_eq!(atomic_instant.fetch_max(low, Ordering::SeqCst), middle);
503 assert_eq!(atomic_instant.load(Ordering::SeqCst), middle);
504 assert_eq!(atomic_instant.fetch_max(middle, Ordering::SeqCst), middle);
505 assert_eq!(atomic_instant.load(Ordering::SeqCst), middle);
506 assert_eq!(atomic_instant.fetch_max(high, Ordering::SeqCst), middle);
507 assert_eq!(atomic_instant.load(Ordering::SeqCst), high);
508 }
509
510 #[test]
511 fn test_atomic_instant_always_lock_free_implies_lock_free() {
512 assert!(!AtomicInstant::is_always_lock_free() || AtomicInstant::is_lock_free());
513 }
514
515 #[test]
516 fn test_atomic_instant_thread_safety() {
517 use std::sync::Arc;
518 use std::thread;
519
520 let start = Instant::now();
527 let atomic_instant = Arc::new(AtomicInstant::new(start));
528 let mut handles = vec![];
529
530 for _ in 0..4 {
531 let atomic_clone = atomic_instant.clone();
532 let handle = thread::spawn(move || {
533 atomic_clone
536 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |current| {
537 Some(current + Duration::from_millis(50))
538 })
539 .expect("closure never returns None");
540 });
541 handles.push(handle);
542 }
543
544 for handle in handles {
545 handle.join().unwrap();
546 }
547
548 assert_eq!(
550 atomic_instant.load(Ordering::SeqCst),
551 start + Duration::from_millis(200)
552 );
553 }
554
555 #[test]
556 fn test_atomic_instant_debug() {
557 let atomic_instant = AtomicInstant::now();
558 let debug_str = format!("{:?}", atomic_instant);
559 assert!(debug_str.contains("AtomicInstant"));
560 }
561
562 #[test]
563 fn test_atomic_instant_from() {
564 let now = Instant::now();
565 let atomic_instant = AtomicInstant::from(now);
566 assert_eq!(atomic_instant.load(Ordering::SeqCst), now);
567 }
568
569 #[test]
570 fn test_atomic_instant_into_inner() {
571 let now = Instant::now();
572 let atomic_instant = AtomicInstant::new(now);
573 assert_eq!(atomic_instant.into_inner(), now);
574 }
575
576 #[test]
577 fn test_atomic_instant_compare_exchange_failure() {
578 let now = Instant::now();
579 let other = now + Duration::from_secs(5);
580 let atomic_instant = AtomicInstant::new(now);
581 let result = atomic_instant.compare_exchange(other, other, Ordering::SeqCst, Ordering::SeqCst);
582 assert!(result.is_err());
583 assert_eq!(result.unwrap_err(), now);
584 }
585
586 #[test]
587 fn test_atomic_instant_fetch_update_failure() {
588 let now = Instant::now();
589 let atomic_instant = AtomicInstant::new(now);
590 let result = atomic_instant.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None);
591 assert!(result.is_err());
592 assert_eq!(result.unwrap_err(), now);
593 }
594
595 #[cfg(feature = "serde")]
596 #[test]
597 fn test_atomic_instant_serde_round_trip_past_and_future() {
598 let now = Instant::now();
599 for instant in [
600 now.checked_sub(Duration::from_secs(1)).unwrap(),
601 now.checked_add(Duration::from_secs(1)).unwrap(),
602 ] {
603 let atomic = AtomicInstant::new(instant);
604 let serialized = serde_json::to_string(&atomic).unwrap();
605 let deserialized: AtomicInstant = serde_json::from_str(&serialized).unwrap();
606 assert_eq!(deserialized.load(Ordering::SeqCst), instant);
607 }
608 }
609
610 #[cfg(feature = "serde")]
611 #[test]
612 fn test_atomic_instant_serde_matches_duration_wire_model() {
613 let instant = Instant::now();
614 let atomic = AtomicInstant::new(instant);
615 let wire_model = crate::utils::encode_instant_to_duration(instant);
616 assert_eq!(
617 serde_json::to_string(&atomic).unwrap(),
618 serde_json::to_string(&wire_model).unwrap()
619 );
620 }
621
622 #[test]
623 fn test_atomic_instant_past_value() {
624 use std::thread;
625
626 let past = Instant::now();
627 thread::sleep(Duration::from_millis(10));
628 let now = Instant::now();
629
630 let atomic = AtomicInstant::new(now);
632 atomic.store(past, Ordering::SeqCst);
633 let loaded = atomic.load(Ordering::SeqCst);
634 assert!(loaded < now);
635 assert_eq!(loaded, past);
636 }
637
638 #[test]
639 fn decode_extreme_instant_falls_back_to_baseline() {
640 let max_dur = Duration::new(u64::MAX, 999_999_999);
643 let decoded = crate::utils::decode_instant_from_duration(max_dur);
644 let other_extreme = Duration::new(u64::MAX, 999_999_998);
645 assert_eq!(
646 decoded,
647 crate::utils::decode_instant_from_duration(other_extreme)
648 );
649 }
650
651 #[cfg(feature = "serde")]
652 #[test]
653 fn deserialize_extreme_instant_uses_baseline_fallback() {
654 let json = r#"{"secs":18446744073709551615,"nanos":999999999}"#;
657 let result: Result<AtomicInstant, _> = serde_json::from_str(json);
658 let atomic = result.expect("extreme Instant deserialization remains Ok");
659 assert_eq!(
660 atomic.load(Ordering::SeqCst),
661 crate::utils::decode_instant_from_duration(Duration::new(u64::MAX, 999_999_999))
662 );
663 }
664}