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}