torrust_clock/clock/stopped/
mod.rs1#[allow(clippy::module_name_repetitions)]
4pub struct StoppedClock {}
5
6#[allow(clippy::module_name_repetitions)]
7pub trait Stopped: clock::Time {
8 fn local_set(unix_time: &DurationSinceUnixEpoch);
10
11 fn local_set_to_unix_epoch() {
13 Self::local_set(&DurationSinceUnixEpoch::ZERO);
14 }
15
16 fn local_set_to_app_start_time();
18
19 fn local_set_to_system_time_now();
21
22 fn local_add(duration: &Duration) -> Result<(), IntErrorKind>;
28
29 fn local_sub(duration: &Duration) -> Result<(), IntErrorKind>;
34
35 fn local_reset();
37}
38
39use std::num::IntErrorKind;
40use std::time::Duration;
41
42use super::{DurationSinceUnixEpoch, Time};
43use crate::clock;
44
45impl Time for clock::Stopped {
46 fn now() -> DurationSinceUnixEpoch {
47 detail::FIXED_TIME.with(|time| {
48 return *time.borrow();
49 })
50 }
51
52 fn dbg_clock_type() -> String {
53 "Stopped".to_owned()
54 }
55}
56
57impl Stopped for clock::Stopped {
58 fn local_set(unix_time: &DurationSinceUnixEpoch) {
59 detail::FIXED_TIME.with(|time| {
60 *time.borrow_mut() = *unix_time;
61 });
62 }
63
64 fn local_set_to_app_start_time() {
65 Self::local_set(&detail::get_app_start_time());
66 }
67
68 fn local_set_to_system_time_now() {
69 Self::local_set(&detail::get_app_start_time());
70 }
71
72 fn local_add(duration: &Duration) -> Result<(), IntErrorKind> {
73 detail::FIXED_TIME.with(|time| {
74 let time_borrowed = *time.borrow();
75 *time.borrow_mut() = match time_borrowed.checked_add(*duration) {
76 Some(time) => time,
77 None => {
78 return Err(IntErrorKind::PosOverflow);
79 }
80 };
81 Ok(())
82 })
83 }
84
85 fn local_sub(duration: &Duration) -> Result<(), IntErrorKind> {
86 detail::FIXED_TIME.with(|time| {
87 let time_borrowed = *time.borrow();
88 *time.borrow_mut() = match time_borrowed.checked_sub(*duration) {
89 Some(time) => time,
90 None => {
91 return Err(IntErrorKind::NegOverflow);
92 }
93 };
94 Ok(())
95 })
96 }
97
98 fn local_reset() {
99 Self::local_set(&detail::get_default_fixed_time());
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use std::thread;
106 use std::time::Duration;
107
108 use crate::DurationSinceUnixEpoch;
109 use crate::clock::stopped::Stopped as _;
110 use crate::clock::{Stopped, Time, Working};
111
112 #[test]
113 fn it_should_default_to_zero_when_testing() {
114 assert_eq!(Stopped::now(), DurationSinceUnixEpoch::ZERO);
115 }
116
117 #[test]
118 fn it_should_possible_to_set_the_time() {
119 assert_eq!(Stopped::now(), Duration::ZERO);
121
122 let timestamp = Working::now();
124 Stopped::local_set(×tamp);
125 assert_eq!(Stopped::now(), timestamp);
126
127 Stopped::local_add(×tamp).unwrap();
129 assert_eq!(Stopped::now(), timestamp + timestamp);
130
131 Stopped::local_reset();
133 assert_eq!(Stopped::now(), Duration::ZERO);
134 }
135
136 #[test]
137 fn it_should_default_to_zero_on_thread_exit() {
138 assert_eq!(Stopped::now(), Duration::ZERO);
139 let after5 = Working::now_add(&Duration::from_secs(5)).unwrap();
140 Stopped::local_set(&after5);
141 assert_eq!(Stopped::now(), after5);
142
143 let t = thread::spawn(move || {
144 assert_eq!(Stopped::now(), Duration::ZERO);
146
147 let timestamp = Working::now();
149 Stopped::local_set(×tamp);
150 assert_eq!(Stopped::now(), timestamp);
151 });
152
153 t.join().unwrap();
155
156 assert_eq!(Stopped::now(), after5);
158
159 Stopped::local_reset();
161 assert_eq!(Stopped::now(), Duration::ZERO);
162 }
163}
164
165mod detail {
166 use std::cell::RefCell;
167 use std::time::SystemTime;
168
169 use crate::{DurationSinceUnixEpoch, static_time};
170
171 thread_local!(pub static FIXED_TIME: RefCell<DurationSinceUnixEpoch> = RefCell::new(get_default_fixed_time()));
172
173 pub fn get_app_start_time() -> DurationSinceUnixEpoch {
174 (*static_time::TIME_AT_APP_START)
175 .duration_since(SystemTime::UNIX_EPOCH)
176 .unwrap()
177 }
178
179 #[cfg(not(test))]
180 pub fn get_default_fixed_time() -> DurationSinceUnixEpoch {
181 get_app_start_time()
182 }
183
184 #[cfg(test)]
185 pub fn get_default_fixed_time() -> DurationSinceUnixEpoch {
186 DurationSinceUnixEpoch::ZERO
187 }
188
189 #[cfg(test)]
190 mod tests {
191 use std::time::Duration;
192
193 use crate::clock::stopped::detail::{get_app_start_time, get_default_fixed_time};
194
195 #[test]
196 fn it_should_get_the_zero_start_time_when_testing() {
197 assert_eq!(get_default_fixed_time(), Duration::ZERO);
198 }
199
200 #[test]
201 fn it_should_get_app_start_time() {
202 const TIME_AT_WRITING_THIS_TEST: Duration = Duration::new(1_662_983_731, 22312);
203 assert!(get_app_start_time() > TIME_AT_WRITING_THIS_TEST);
204 }
205 }
206}