qubit_clock/clock/controllable_clock.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! Controllable clock trait for testing.
11//!
12//! This module defines the [`ControllableClock`] trait, which extends
13//! [`Clock`] to provide methods for controlling the clock's time. This is
14//! primarily useful for testing scenarios.
15//!
16
17use crate::Clock;
18use chrono::{
19 DateTime,
20 Duration,
21 Utc,
22};
23
24/// A trait representing a clock that can be controlled.
25///
26/// This trait extends [`Clock`] to provide methods for manually setting and
27/// advancing the clock's time. It's primarily designed for testing scenarios
28/// where you need precise control over time.
29///
30/// # Warning
31///
32/// This trait should only be used in testing code, not in production code.
33///
34/// # Examples
35///
36/// ```
37/// use qubit_clock::{Clock, ControllableClock, MockClock};
38/// use chrono::{DateTime, Duration, Utc};
39///
40/// let clock = MockClock::new();
41///
42/// // Set to a specific time
43/// let fixed_time = DateTime::parse_from_rfc3339(
44/// "2024-01-01T00:00:00Z"
45/// ).unwrap().with_timezone(&Utc);
46/// clock.set_time(fixed_time);
47///
48/// assert_eq!(clock.time(), fixed_time);
49///
50/// // Advance by 1 hour
51/// clock.add_duration(Duration::hours(1));
52/// assert_eq!(
53/// clock.time(),
54/// fixed_time + Duration::hours(1)
55/// );
56/// ```
57///
58pub trait ControllableClock: Clock {
59 /// Sets or aligns the clock to a specific time.
60 ///
61 /// The exact semantics depend on the implementation. For
62 /// [`MockClock`](crate::MockClock), this reanchors the current timeline
63 /// instant to read as `instant` without changing elapsed mock time.
64 ///
65 /// # Arguments
66 ///
67 /// * `instant` - The time to set the clock to (UTC).
68 ///
69 /// # Examples
70 ///
71 /// ```
72 /// use qubit_clock::{Clock, ControllableClock, MockClock};
73 /// use chrono::{DateTime, Utc};
74 ///
75 /// let clock = MockClock::new();
76 /// let time = DateTime::parse_from_rfc3339(
77 /// "2024-01-01T00:00:00Z"
78 /// ).unwrap().with_timezone(&Utc);
79 ///
80 /// clock.set_time(time);
81 /// assert_eq!(clock.time(), time);
82 /// ```
83 fn set_time(&self, instant: DateTime<Utc>);
84
85 /// Advances the clock by the specified duration.
86 ///
87 /// Implementations may reject durations they cannot represent. For
88 /// [`MockClock`](crate::MockClock), negative durations panic because mock
89 /// timeline time is monotonic.
90 ///
91 /// # Arguments
92 ///
93 /// * `duration` - The duration to advance the clock by.
94 ///
95 /// # Examples
96 ///
97 /// ```
98 /// use qubit_clock::{Clock, ControllableClock, MockClock};
99 /// use chrono::Duration;
100 ///
101 /// let clock = MockClock::new();
102 /// let before = clock.time();
103 ///
104 /// clock.add_duration(Duration::hours(1));
105 ///
106 /// let after = clock.time();
107 /// assert_eq!(after - before, Duration::hours(1));
108 /// ```
109 fn add_duration(&self, duration: Duration);
110
111 /// Resets the clock to its initial state.
112 ///
113 /// The exact behavior of this method depends on the implementation. For
114 /// [`MockClock`](crate::MockClock), it resets the shared mock timeline and
115 /// wall-clock anchor captured when the clock was created.
116 ///
117 /// # Examples
118 ///
119 /// ```
120 /// use qubit_clock::{Clock, ControllableClock, MockClock};
121 /// use chrono::Duration;
122 ///
123 /// let clock = MockClock::new();
124 /// let initial = clock.time();
125 ///
126 /// clock.add_duration(Duration::hours(1));
127 /// clock.reset();
128 ///
129 /// // After reset, time should return to the initial frozen value.
130 /// assert_eq!(clock.time(), initial);
131 /// ```
132 fn reset(&self);
133}