Skip to main content

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 progression semantics depend on the implementation. For
62    /// [`MockClock`](crate::MockClock) and
63    /// [`MockNanoClock`](crate::MockNanoClock), this reanchors the current
64    /// logical reading to `instant` while preserving the current progression
65    /// and auto-advance settings.
66    ///
67    /// # Arguments
68    ///
69    /// * `instant` - The time to set the clock to (UTC).
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use qubit_clock::{Clock, ControllableClock, MockClock};
75    /// use chrono::{DateTime, Utc};
76    ///
77    /// let clock = MockClock::new();
78    /// let time = DateTime::parse_from_rfc3339(
79    ///     "2024-01-01T00:00:00Z"
80    /// ).unwrap().with_timezone(&Utc);
81    ///
82    /// clock.set_time(time);
83    /// assert_eq!(clock.time(), time);
84    /// ```
85    fn set_time(&self, instant: DateTime<Utc>);
86
87    /// Advances the clock by the specified duration.
88    ///
89    /// # Arguments
90    ///
91    /// * `duration` - The duration to advance the clock by.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// use qubit_clock::{Clock, ControllableClock, MockClock};
97    /// use chrono::Duration;
98    ///
99    /// let clock = MockClock::new();
100    /// let before = clock.time();
101    ///
102    /// clock.add_duration(Duration::hours(1));
103    ///
104    /// let after = clock.time();
105    /// assert_eq!(after - before, Duration::hours(1));
106    /// ```
107    fn add_duration(&self, duration: Duration);
108
109    /// Resets the clock to its initial state.
110    ///
111    /// The exact behavior of this method depends on the implementation. For
112    /// [`MockClock`](crate::MockClock) and
113    /// [`MockNanoClock`](crate::MockNanoClock), it resets to the logical
114    /// reading and progression mode captured when the clock was created.
115    ///
116    /// # Examples
117    ///
118    /// ```
119    /// use qubit_clock::{Clock, ControllableClock, MockClock};
120    /// use chrono::Duration;
121    ///
122    /// let clock = MockClock::new();
123    /// let initial = clock.time();
124    ///
125    /// clock.add_duration(Duration::hours(1));
126    /// clock.reset();
127    ///
128    /// // After reset, time should return to the initial frozen value.
129    /// assert_eq!(clock.time(), initial);
130    /// ```
131    fn reset(&self);
132}