tick 0.3.3

Provides primitives to interact with and manipulate machine time.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use std::task::Waker;
use std::time::{Duration, Instant, SystemTime};

use thread_aware::ThreadAware;
use thread_aware::affinity::Affinity;

use crate::state::ClockState;
use crate::timers::TimerKey;

/// Provides an abstraction for time-related operations.
///
/// Working with time is notoriously difficult to test and control. The clock enables time control in tests
/// while providing zero-cost overhead in production. When the `test-util` feature is enabled, the clock
/// provides additional functionality to control the passage of time. This makes tests faster and more reliable.
/// See the [Testing](#testing) section for more information.
///
/// The clock is used for:
///
/// - Retrieving the current absolute time in UTC.
/// - Creating [`Stopwatch`][super::Stopwatch] instances that
///   simplify time measurements and can be used as relative units of time.
/// - Creating [`PeriodicTimer`][super::PeriodicTimer] and [`Delay`][super::Delay] instances.
///
/// # Relative and absolute time
///
/// The clock provides two types of time representation:
///
/// - [`Stopwatch`][super::Stopwatch]: Represents relative time that is monotonic. Useful for measuring
///   elapsed time. Prefer relative time when a point in time does not cross process boundaries.
/// - Absolute time: Represents an absolute point in time in UTC via [`SystemTime`]. Use this when you need
///   absolute time support or need to interoperate with other crates using `SystemTime`. With the `fmt` feature
///   enabled, you can format `SystemTime` into different formats.
///
/// Absolute time is not monotonic and can be affected by system clock changes.
///
/// When possible, always prefer [`Stopwatch`][super::Stopwatch] over absolute time due to its monotonic properties.
/// For scenarios where you need absolute time, use [`system_time()`][Self::system_time].
///
/// # Clock construction
///
/// The clock requires a runtime to drive the registered timers. This crate provides built-in support
/// for Tokio via [`Clock::new_tokio()`] (available with the `tokio` feature). For other async runtimes,
/// you can use types in the [`runtime`][crate::runtime] module to drive the clock.
///
/// In tests, the clock can be constructed directly using [`ClockControl`][crate::ClockControl] or via [`Clock::new_frozen`][crate::Clock::new_frozen]
/// (available with the `test-util` feature) because the passage of time is controlled manually.
///
/// See the [Testing](#testing) section for more information.
///
/// # Testing
///
/// When working with time, it's challenging to isolate time-related operations in tests. A typical example is the sleep
/// operation, which is hard to test and slows down tests. What you want to do is have complete control over the passage
/// of time that allows you to jump forward in time. This is where the clock comes into play.
///
/// The ability to jump forward in time makes tests faster, more reliable and gives you complete control over the passage of time.
/// By default, the clock does not allow you to control the passage of time. However, when the `test-util` feature is enabled,
/// this crate provides a [`ClockControl`][crate::ClockControl] type that can be used to control time.
///
/// # Cloning and shared state
///
/// Cloning a clock is inexpensive and every clone shares the same underlying state,
/// including registered timers and, when the `test-util` feature is enabled, the controlled passage of time.
/// Any timers you register or time adjustments you perform through one clone are visible to every other clone
/// created from the same clock.
///
/// ```
/// use tick::Clock;
///
/// # fn use_clock(clock: &Clock) {
/// let clock_clone1 = clock.clone();
/// let clock_clone2 = clock.clone();
/// // All clones remain linked and observe the same timers and time control.
/// # }
/// ```
///
/// # Thread-aware relocation
///
/// `Clock` implements [`ThreadAware`](thread_aware::ThreadAware), enabling per-core timer isolation
/// in thread-per-core runtime architectures.
///
/// How relocation affects the clock depends on the underlying clock variant:
///
/// - **System clocks**: Relocation creates per-core timer storage. After relocation, each core
///   maintains its own independent set of timers, eliminating cross-thread lock contention. Clones
///   of a clock on the same core share timers, while clocks relocated to different cores are fully
///   isolated. Each core's timers must be advanced by its own
///   [`ClockDriver`][crate::runtime::ClockDriver].
///
/// - **`ClockControl` clocks** (`test-util`): Relocation is a no-op. All clones share the same
///   controlled time state regardless of which thread they are on. This is intentional, a single
///   [`ClockControl`][crate::ClockControl] controls time for all clocks derived from it, even
///   across threads.
///
/// - **Tokio clocks** (created via [`Clock::new_tokio()`]): Relocation is a no-op. The Tokio clock
///   is driven by a single background task that advances a shared set of timers, so all clones
///   share the same timer storage regardless of which thread they are on. Per-core relocation
///   would create independent timer storage on the destination thread that the background driver
///   does not advance, so relocation is intentionally suppressed.
///
/// For thread-per-core setups, the typical pattern is to clone an
/// [`InactiveClock`][crate::runtime::InactiveClock], relocate each clone to its target thread,
/// and then activate it. See the [`runtime`][crate::runtime] module for details.
///
/// # Examples
///
/// ## Retrieve absolute time
///
/// ```
/// use std::time::SystemTime;
///
/// use tick::Clock;
///
/// # fn retrieve_absolute_time(clock: &Clock) {
/// // Using SystemTime for basic absolute time needs
/// let time1: SystemTime = clock.system_time();
/// let time2: SystemTime = clock.system_time();
///
/// assert!(time2 >= time1);
/// # }
/// ```
///
/// ## Measure elapsed time
///
/// ```
/// use std::time::Duration;
///
/// use tick::Clock;
///
/// # fn measure(clock: &Clock) {
/// let stopwatch = clock.stopwatch();
/// // Perform some operation...
/// let elapsed: Duration = stopwatch.elapsed();
/// # }
/// ```
///
/// ## Delay operations
///
/// ```
/// use std::time::Duration;
///
/// use tick::Clock;
///
/// # async fn delay_example(clock: &Clock) {
/// let stopwatch = clock.stopwatch();
///
/// // Delay for 10 milliseconds
/// clock.delay(Duration::from_millis(10)).await;
///
/// assert!(stopwatch.elapsed() >= Duration::from_millis(10));
/// # }
/// ```
///
/// ## Create periodic timers
///
/// ```
/// use std::time::Duration;
///
/// use futures::StreamExt;
/// use tick::{Clock, PeriodicTimer};
///
/// # async fn timer_example(clock: &Clock) {
/// let mut timer = PeriodicTimer::new(&clock, Duration::from_millis(10));
///
/// while let Some(()) = timer.next().await {
///     // do something
///         # break;
/// }
/// # }
/// ```
#[derive(Clone)]
pub struct Clock {
    state: ClockState,
    affinity: Option<Affinity>,
}

impl std::fmt::Debug for Clock {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let kind = match &self.state {
            #[cfg(any(feature = "test-util", test))]
            ClockState::ClockControl(_) => "controlled",
            ClockState::System(_) => "system",
        };

        f.debug_struct("Clock")
            .field("kind", &kind)
            .field("timers", &self.state.timers_len())
            .field("alive", &self.state.alive())
            .field("affinity", &self.affinity)
            .finish_non_exhaustive()
    }
}

impl ThreadAware for Clock {
    fn relocate(&mut self, source: Option<Affinity>, destination: Affinity) {
        self.state.relocate(source, destination);
        self.affinity = Some(destination);
    }
}

impl Clock {
    /// Creates a new clock driven by the Tokio runtime.
    ///
    /// # Panics
    ///
    /// Panics if called outside of a Tokio runtime context.
    #[cfg(any(feature = "tokio", test))]
    #[must_use]
    #[cfg_attr(test, mutants::skip)] // Causes test timeout.
    pub fn new_tokio() -> Self {
        Self::new_tokio_core().0
    }

    pub(crate) fn new(state: ClockState) -> Self {
        Self { state, affinity: None }
    }

    #[cfg(any(feature = "tokio", test))]
    fn new_tokio_core() -> (Self, tokio::task::JoinHandle<()>) {
        /// How often the Tokio clock driver advances timers.
        ///
        /// A 10ms resolution balances precision with runtime overhead for the
        /// background task that drives timer advancement in Tokio.
        const TIMER_RESOLUTION: Duration = Duration::from_millis(10);

        // The Tokio clock is driven by a single background task that advances a shared timer
        // set. We use the `Shared` inactive-clock variant which intentionally does not support
        // cloning or per-core relocation, since both would create configurations the single
        // background driver could not advance correctly.
        let (clock, mut driver) = crate::runtime::InactiveClock::new_shared().activate();

        let join_handle = tokio::spawn(async move {
            loop {
                tokio::time::sleep(TIMER_RESOLUTION).await;

                if driver.advance_timers(Instant::now()).is_err() {
                    break;
                }
            }
        });

        (clock, join_handle)
    }

    /// Used for testing. For this clock, timers do not advance.
    #[cfg(test)]
    pub(super) fn new_system_frozen() -> Self {
        Self::new(ClockState::new_system())
    }

    /// Creates a new frozen clock.
    ///
    /// This is a convenience method equivalent to calling `ClockControl::new().to_clock()`.
    ///
    /// > **Note**: The returned clock will not advance time; all time and timers are frozen.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::thread::sleep;
    /// use std::time::Duration;
    ///
    /// use tick::Clock;
    ///
    /// let clock = Clock::new_frozen();
    ///
    /// // The clock will always return the same timestamp and instant.
    /// let system_time = clock.system_time();
    /// let instance = clock.instant();
    ///
    /// sleep(Duration::from_micros(1));
    ///
    /// assert_eq!(system_time, clock.system_time());
    /// assert_eq!(instance, clock.instant());
    /// ```
    #[cfg(any(feature = "test-util", test))]
    #[must_use]
    pub fn new_frozen() -> Self {
        crate::ClockControl::new().to_clock()
    }

    /// Creates a new frozen clock at the specified timestamp.
    ///
    /// This is a convenience method equivalent to calling `ClockControl::new_at(time).to_clock()`.
    ///
    /// > **Note**: The returned clock will not advance time; all time and timers are frozen at the specified timestamp.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::time::{Duration, SystemTime};
    ///
    /// use tick::Clock;
    ///
    /// let specific_time = SystemTime::UNIX_EPOCH + Duration::from_secs(1_000_000);
    /// let clock = Clock::new_frozen_at(specific_time);
    ///
    /// // The clock will always return the same timestamp and instant.
    /// let system_time = clock.system_time();
    ///
    /// assert_eq!(system_time, specific_time);
    /// assert_eq!(system_time, clock.system_time());
    /// ```
    #[cfg(any(feature = "test-util", test))]
    #[must_use]
    pub fn new_frozen_at(time: impl Into<SystemTime>) -> Self {
        crate::ClockControl::new_at(time).to_clock()
    }

    /// Retrieves the current system time as [`SystemTime`].
    ///
    /// > **Note**: The system time is not monotonic and can be affected by system clock changes.
    /// > When the system clock changes, the current time may be older than a previously retrieved one.
    /// > For relative time measurements, use [`Stopwatch`][super::Stopwatch].
    ///
    /// # Examples
    ///
    /// ```
    /// use tick::Clock;
    ///
    /// # fn retrieve_system_time(clock: &Clock) {
    /// let time1 = clock.system_time();
    /// let time2 = clock.system_time();
    ///
    /// assert!(time2 >= time1);
    /// # }
    /// ```
    #[must_use]
    pub fn system_time(&self) -> SystemTime {
        match self.clock_state() {
            #[cfg(any(feature = "test-util", test))]
            ClockState::ClockControl(control) => control.system_time(),
            ClockState::System(_) => SystemTime::now(),
        }
    }

    /// Retrieves the current system time converted to a target type.
    ///
    /// This is a convenience method that retrieves the current [`SystemTime`] via
    /// [`system_time()`][Self::system_time] and converts it to the specified target type.
    ///
    /// # Type Parameters
    ///
    /// * `T` - The target type that implements [`TryFrom<SystemTime>`]. Common examples include
    ///   timestamp types from external crates that can be constructed from a [`SystemTime`].
    ///
    /// # Panics
    ///
    /// While this method uses [`TryFrom`] (a fallible conversion), it may panic on conversion failure.
    ///
    /// In practice, this conversion always succeeds because:
    ///
    /// - The system time returned is always within a normalized range in real environments.
    /// - Target types that implement [`TryFrom<SystemTime>`][TryFrom] typically support the full valid
    ///   range of system time values.
    ///
    /// The only theoretical failure case is in tests using manual time control (via the
    /// `test-util` feature), where time could be moved excessively far into the future,
    /// potentially exceeding the target type's supported range of values. This is not a concern
    /// in production.
    #[expect(
        clippy::match_wild_err_arm,
        clippy::panic,
        reason = "the panic might only occur when system time is outside of valid range which won't ever happen in real environments"
    )]
    #[must_use]
    pub fn system_time_as<T: TryFrom<SystemTime>>(&self) -> T {
        match T::try_from(self.system_time()) {
            Ok(time) => time,
            Err(_err) => panic!(
                "The SystemTime returned by the clock is always in normalized range and must be convertible to the target type.
                If the target type overflows, it indicates a problem with the target type not supporting valid system time range or
                we are in tests where the time was moved excessively into the future. Practically, in production, this conversion will
                always succeed.",
            ),
        }
    }

    /// Retrieves the current [`Instant`] time.
    ///
    /// An [`Instant`] represents a monotonic time point guaranteed to always increase.
    /// Unlike [`system_time`][Self::system_time], the instant is not affected by system clock
    /// changes and provides a stable reference point for measuring elapsed time.
    ///
    /// > **Note**: For time measurements, consider using [`Stopwatch`][super::Stopwatch] instead,
    /// > which provides a more convenient API for measuring elapsed time.
    ///
    /// > **Important**: When measuring elapsed time with [`Instant`], use [`Instant::duration_since`]
    /// > rather than `Instant::elapsed`. The `elapsed` method bypasses the clock and goes directly
    /// > to system time, which means it won't respect controlled time in tests or when using
    /// > `ClockControl`.
    ///
    /// # Examples
    ///
    /// ```
    /// use tick::Clock;
    ///
    /// # fn retrieve_instant(clock: &Clock) {
    /// let instant1 = clock.instant();
    /// let instant2 = clock.instant();
    ///
    /// assert!(instant2 >= instant1);
    /// # }
    /// ```
    #[must_use]
    pub fn instant(&self) -> Instant {
        match self.clock_state() {
            #[cfg(any(feature = "test-util", test))]
            ClockState::ClockControl(control) => control.instant(),
            ClockState::System(_) => Instant::now(),
        }
    }

    /// Creates a new [`Delay`][crate::Delay] that will complete after the specified duration.
    ///
    /// This is a convenience method that calls [`Delay::new`][crate::Delay::new].
    ///
    /// If the duration is [`Duration::ZERO`], the delay completes immediately.
    /// If the duration is [`Duration::MAX`], the delay never completes.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::time::Duration;
    ///
    /// use tick::Clock;
    ///
    /// # async fn delay_example(clock: &Clock) {
    /// let stopwatch = clock.stopwatch();
    ///
    /// // Delay for 10 milliseconds
    /// clock.delay(Duration::from_millis(10)).await;
    ///
    /// assert!(stopwatch.elapsed() >= Duration::from_millis(10));
    /// # }
    /// ```
    #[must_use]
    pub fn delay(&self, duration: Duration) -> crate::Delay {
        crate::Delay::new(self, duration)
    }

    /// Creates a new [`Stopwatch`][crate::Stopwatch] that starts measuring elapsed time.
    ///
    /// This is a convenience method that calls [`Stopwatch::new`][crate::Stopwatch::new].
    ///
    /// # Examples
    ///
    /// ```
    /// use std::time::Duration;
    ///
    /// use tick::Clock;
    ///
    /// # async fn stopwatch_example(clock: &Clock) {
    /// let stopwatch = clock.stopwatch();
    ///
    /// // Perform some operation...
    /// clock.delay(Duration::from_millis(10)).await;
    ///
    /// assert!(stopwatch.elapsed() >= Duration::from_millis(10));
    /// # }
    /// ```
    #[must_use]
    pub fn stopwatch(&self) -> crate::Stopwatch {
        crate::Stopwatch::new(self)
    }

    pub(super) fn register_timer(&self, when: Instant, waker: Waker) -> TimerKey {
        match self.clock_state() {
            #[cfg(any(feature = "test-util", test))]
            ClockState::ClockControl(control) => control.register_timer(when, waker),
            ClockState::System(timers) => timers.with_timers(|t| t.register(when, waker)),
        }
    }

    pub(super) fn unregister_timer(&self, key: TimerKey) {
        match self.clock_state() {
            #[cfg(any(feature = "test-util", test))]
            ClockState::ClockControl(control) => control.unregister_timer(key),
            ClockState::System(timers) => timers.with_timers(|t| t.unregister(key)),
        }
    }

    pub(crate) fn clock_state(&self) -> &ClockState {
        &self.state
    }
}

impl AsRef<Self> for Clock {
    fn as_ref(&self) -> &Self {
        self
    }
}

#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
    #![allow(clippy::arithmetic_side_effects, reason = "no need to be strict in tests")]

    use std::fmt::Debug;
    use std::task::Context;
    use std::thread::sleep;

    use futures::FutureExt;
    use thread_aware::affinity::pinned_affinities;

    use super::*;
    use crate::ClockControl;
    use crate::runtime::InactiveClock;

    static_assertions::assert_impl_all!(Clock: Debug, Send, Sync, Clone, AsRef<Clock>);

    #[test]
    fn assert_types() {
        static_assertions::assert_impl_all!(Clock: Send, Sync, AsRef<Clock>);
    }

    #[cfg_attr(miri, ignore)] // Miri is not compatible with FFI calls this needs to make.
    #[test]
    fn test_now() {
        let now = std::time::SystemTime::now();

        let clock = Clock::new_system_frozen();
        let absolute = clock.system_time();
        assert!(absolute >= now);
    }

    #[test]
    fn test_now_with_control() {
        let control = ClockControl::new();
        let clock = control.to_clock();

        let now = clock.system_time();
        assert_eq!(now, control.system_time());

        () = control.advance(Duration::from_secs(10));

        assert_eq!(clock.system_time(), now.checked_add(Duration::from_secs(10)).unwrap());
    }

    #[test]
    fn test_instant_now() {
        let clock = Clock::new_system_frozen();
        let clock_instant = clock.instant();
        let system_instant = Instant::now();

        assert!(
            (system_instant.duration_since(clock_instant)) < Duration::from_secs(10),
            "the `Instant` retrieved from the clock is not the same as the system one"
        );
    }

    #[cfg_attr(miri, ignore)] // Miri is not compatible with FFI calls this needs to make.
    #[test]
    fn test_system_time() {
        let now = std::time::SystemTime::now();

        let clock = Clock::new_system_frozen();
        let system_time = clock.system_time();
        assert!(system_time >= now);
    }

    #[test]
    fn test_system_time_with_control() {
        let control = ClockControl::new();
        let clock = control.to_clock();

        let system_time = clock.system_time();
        assert_eq!(system_time, control.system_time());

        () = control.advance(Duration::from_secs(10));

        assert_eq!(clock.system_time(), control.system_time());
    }

    #[cfg_attr(miri, ignore)] // The logic we call talks to the real OS, which Miri cannot do.
    #[tokio::test]
    async fn tokio_ensure_timers_advancing() {
        let clock = Clock::new_tokio();
        clock.delay(Duration::from_millis(15)).await;
    }

    #[cfg_attr(miri, ignore)] // The logic we call talks to the real OS, which Miri cannot do.
    #[tokio::test]
    async fn tokio_ensure_timers_advancing_after_relocate() {
        // Relocation must be a no-op for Tokio clocks: the background driver task drives a
        // shared timer set, so a relocated clone must still observe timers being advanced.
        let affinities = pinned_affinities(&[2]);
        let clock = Clock::new_tokio();
        let mut clock = clock;
        clock.relocate(Some(affinities[0]), affinities[1]);
        clock.delay(Duration::from_millis(15)).await;
    }

    #[cfg_attr(miri, ignore)] // The logic we call talks to the real OS, which Miri cannot do.
    #[tokio::test]
    async fn tokio_ensure_future_finished_when_clock_dropped() {
        let (clock, handle) = Clock::new_tokio_core();

        clock.delay(Duration::from_millis(15)).await;

        drop(clock);

        handle.await.unwrap();
    }

    #[test]
    fn new_frozen_ok() {
        let clock = Clock::new_frozen();

        let now = clock.system_time();
        let instant = clock.instant();

        sleep(Duration::from_micros(1));

        // The frozen clock should return the same timestamp and instant on every call
        assert_eq!(now, clock.system_time());
        assert_eq!(instant, clock.instant());
    }

    #[test]
    fn new_frozen_at_ok() {
        let specific_time = SystemTime::UNIX_EPOCH + Duration::from_secs(1_000_000);
        let clock = Clock::new_frozen_at(specific_time);

        let timestamp = clock.system_time();
        let system_time = clock.system_time();

        sleep(Duration::from_micros(1));

        // The frozen clock should return the same timestamp and system time on every call
        assert_eq!(system_time, specific_time);
        assert_eq!(timestamp, clock.system_time());
        assert_eq!(system_time, clock.system_time());
    }

    #[test]
    #[should_panic(expected = "The SystemTime returned by the clock is always in normalized range")]
    fn system_time_as_panics_on_conversion_failure() {
        /// A newtype that always fails conversion from `SystemTime`.
        struct AlwaysFailsConversion;

        impl TryFrom<SystemTime> for AlwaysFailsConversion {
            type Error = &'static str;

            fn try_from(_: SystemTime) -> Result<Self, Self::Error> {
                Err("conversion always fails")
            }
        }

        let clock = Clock::new_frozen();
        let _: AlwaysFailsConversion = clock.system_time_as();
    }

    #[test]
    fn as_ref_ok() {
        let clock = Clock::new_frozen();
        let _: &Clock = clock.as_ref();
    }

    #[test]
    fn owners_count() {
        let (clock, driver) = InactiveClock::default().activate();

        assert!(!clock.state.is_unique());
        drop(clock);
        assert!(driver.state.is_unique());
    }

    #[test]
    fn owners_count_clock_control() {
        let (clock, driver) = InactiveClock::from(ClockControl::default()).activate();

        assert!(!driver.state.is_unique());
        drop(clock);
        assert!(driver.state.is_unique());
    }

    #[test]
    fn thread_aware() {
        let affinites = pinned_affinities(&[1, 1]);
        let source = Some(affinites[0]);
        let pinned_1 = affinites[0];
        let pinned_2 = affinites[1];

        // root clock
        let root = InactiveClock::default();

        let mut inactive_1 = root.clone();
        inactive_1.relocate(source, pinned_1);
        let mut inactive_2 = root;
        inactive_2.relocate(source, pinned_2);

        let (clock_1, mut driver_1) = inactive_1.activate();
        let (clock_2, mut driver_2) = inactive_2.activate();

        // register the timer on clock 1
        let mut fut_1 = Box::pin(clock_1.delay(Duration::from_secs(100)));
        _ = fut_1.poll_unpin(&mut Context::from_waker(Waker::noop()));
        assert_eq!(clock_1.state.timers_len(), 1);
        assert_eq!(clock_2.state.timers_len(), 0);
        assert_eq!(driver_1.state.timers_len(), 1);
        assert_eq!(driver_2.state.timers_len(), 0);
        {
            let mut relocated_clock = clock_1.clone();
            relocated_clock.relocate(source, pinned_2);
            assert_eq!(relocated_clock.state.timers_len(), 0);
        }

        // register the timer on clock 2
        let mut fut_2 = Box::pin(clock_2.delay(Duration::from_secs(100)));
        _ = fut_2.poll_unpin(&mut Context::from_waker(Waker::noop()));
        assert_eq!(clock_1.state.timers_len(), 1);
        assert_eq!(clock_2.state.timers_len(), 1);
        assert_eq!(driver_1.state.timers_len(), 1);
        assert_eq!(driver_2.state.timers_len(), 1);

        // advance timers
        driver_1.advance_timers(Instant::now() + Duration::from_secs(200)).unwrap();
        assert_eq!(driver_1.state.timers_len(), 0);
        assert_eq!(driver_2.state.timers_len(), 1);
        driver_2.advance_timers(Instant::now() + Duration::from_secs(200)).unwrap();
        assert_eq!(driver_2.state.timers_len(), 0);

        drop(fut_1);
        drop(fut_2);

        // drop clock
        drop(clock_1);
        driver_1.advance_timers(Instant::now()).unwrap_err();
        driver_2.advance_timers(Instant::now()).unwrap();
        drop(clock_2);
        driver_2.advance_timers(Instant::now()).unwrap_err();
    }

    #[test]
    fn thread_aware_clock_control() {
        let affinites = pinned_affinities(&[1, 1]);
        let source = Some(affinites[0]);
        let pinned_1 = affinites[0];
        let pinned_2 = affinites[1];

        // root clock
        let root: InactiveClock = ClockControl::default().into();

        let mut inactive_1 = root.clone();
        inactive_1.relocate(source, pinned_1);
        let mut inactive_2 = root;
        inactive_2.relocate(source, pinned_2);

        let (clock_1, driver_1) = inactive_1.activate();
        let (clock_2, driver_2) = inactive_2.activate();

        // register the timer on clock 1 also affects clock 2 because clock control is shared
        let mut fut_1 = Box::pin(clock_1.delay(Duration::from_secs(100)));
        _ = fut_1.poll_unpin(&mut Context::from_waker(Waker::noop()));
        assert_eq!(clock_1.state.timers_len(), 1);
        assert_eq!(clock_2.state.timers_len(), 1);
        assert_eq!(driver_1.state.timers_len(), 1);
        assert_eq!(driver_2.state.timers_len(), 1);
    }

    #[test]
    #[cfg_attr(miri, ignore)]
    fn debug_system_clock() {
        let clock = Clock::new_system_frozen();

        insta::assert_debug_snapshot!(clock);
    }

    #[tokio::test]
    #[cfg_attr(miri, ignore)]
    async fn debug_alive_system_clock() {
        let _affinites = pinned_affinities(&[2]);
        let clock = Clock::new_tokio();

        clock.delay(Duration::from_millis(1)).await;

        insta::assert_debug_snapshot!(clock);
    }

    #[tokio::test]
    #[cfg_attr(miri, ignore)]
    async fn debug_alive_system_clock_relocated() {
        let affinites = pinned_affinities(&[2]);
        let mut clock = Clock::new_system_frozen();
        clock.relocate(Some(affinites[0]), affinites[1]);

        insta::assert_debug_snapshot!(clock);
    }

    #[test]
    #[cfg_attr(miri, ignore)]
    fn debug_controlled_clock() {
        let control = ClockControl::new();
        let clock = control.to_clock();
        insta::assert_debug_snapshot!(clock);
    }

    #[test]
    #[cfg_attr(miri, ignore)]
    fn debug_clock_with_timers() {
        let control = ClockControl::new();
        let clock = control.to_clock();

        control.register_timer(Instant::now() + Duration::from_secs(100), Waker::noop().clone());
        control.register_timer(Instant::now() + Duration::from_secs(200), Waker::noop().clone());

        insta::assert_debug_snapshot!(clock);
    }
}