atomic_time/
system_time.rs1use core::sync::atomic::Ordering;
2use std::time::SystemTime;
3
4use crate::AtomicDuration;
5
6#[repr(transparent)]
8pub struct AtomicSystemTime(AtomicDuration);
9
10impl AtomicSystemTime {
11 pub fn now() -> Self {
20 Self::new(SystemTime::now())
21 }
22
23 pub fn new(system_time: SystemTime) -> Self {
29 Self(AtomicDuration::new(
30 system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
31 ))
32 }
33
34 pub fn load(&self, order: Ordering) -> SystemTime {
36 SystemTime::UNIX_EPOCH + self.0.load(order)
37 }
38
39 pub fn store(&self, system_time: SystemTime, order: Ordering) {
45 self.0.store(
46 system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
47 order,
48 )
49 }
50
51 pub fn swap(&self, system_time: SystemTime, order: Ordering) -> SystemTime {
57 SystemTime::UNIX_EPOCH
58 + self.0.swap(
59 system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
60 order,
61 )
62 }
63
64 pub fn compare_exchange(
71 &self,
72 current: SystemTime,
73 new: SystemTime,
74 success: Ordering,
75 failure: Ordering,
76 ) -> Result<SystemTime, SystemTime> {
77 match self.0.compare_exchange(
78 current.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
79 new.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
80 success,
81 failure,
82 ) {
83 Ok(duration) => Ok(SystemTime::UNIX_EPOCH + duration),
84 Err(duration) => Err(SystemTime::UNIX_EPOCH + duration),
85 }
86 }
87
88 pub fn compare_exchange_weak(
95 &self,
96 current: SystemTime,
97 new: SystemTime,
98 success: Ordering,
99 failure: Ordering,
100 ) -> Result<SystemTime, SystemTime> {
101 match self.0.compare_exchange_weak(
102 current.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
103 new.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
104 success,
105 failure,
106 ) {
107 Ok(duration) => Ok(SystemTime::UNIX_EPOCH + duration),
108 Err(duration) => Err(SystemTime::UNIX_EPOCH + duration),
109 }
110 }
111
112 pub fn fetch_update<F>(
151 &self,
152 set_order: Ordering,
153 fetch_order: Ordering,
154 mut f: F,
155 ) -> Result<SystemTime, SystemTime>
156 where
157 F: FnMut(SystemTime) -> Option<SystemTime>,
158 {
159 self
160 .0
161 .fetch_update(set_order, fetch_order, |duration| {
162 f(SystemTime::UNIX_EPOCH + duration)
163 .map(|system_time| system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap())
164 })
165 .map(|duration| SystemTime::UNIX_EPOCH + duration)
166 .map_err(|duration| SystemTime::UNIX_EPOCH + duration)
167 }
168
169 #[inline]
181 pub fn is_lock_free() -> bool {
182 AtomicDuration::is_lock_free()
183 }
184}
185
186#[cfg(feature = "serde")]
187const _: () = {
188 use serde::{Deserialize, Serialize};
189
190 impl Serialize for AtomicSystemTime {
191 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
192 self.load(Ordering::SeqCst).serialize(serializer)
193 }
194 }
195
196 impl<'de> Deserialize<'de> for AtomicSystemTime {
197 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
198 Ok(Self::new(SystemTime::deserialize(deserializer)?))
199 }
200 }
201};
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use std::time::Duration;
207
208 #[test]
209 fn test_atomic_system_time_now() {
210 let atomic_time = AtomicSystemTime::now();
211 assert_ne!(atomic_time.load(Ordering::SeqCst), SystemTime::UNIX_EPOCH);
214 }
215
216 #[test]
217 fn test_atomic_system_time_new_and_load() {
218 let now = SystemTime::now();
219 let atomic_time = AtomicSystemTime::new(now);
220 assert_eq!(atomic_time.load(Ordering::SeqCst), now);
221 }
222
223 #[test]
224 fn test_atomic_system_time_store_and_load() {
225 let now = SystemTime::now();
226 let after_one_sec = now + Duration::from_secs(1);
227 let atomic_time = AtomicSystemTime::new(now);
228 atomic_time.store(after_one_sec, Ordering::SeqCst);
229 assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
230 }
231
232 #[test]
233 fn test_atomic_system_time_swap() {
234 let now = SystemTime::now();
235 let after_one_sec = now + Duration::from_secs(1);
236 let atomic_time = AtomicSystemTime::new(now);
237 let prev_time = atomic_time.swap(after_one_sec, Ordering::SeqCst);
238 assert_eq!(prev_time, now);
239 assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
240 }
241
242 #[test]
243 fn test_atomic_system_time_compare_exchange_weak() {
244 let now = SystemTime::now();
245 let after_one_sec = now + Duration::from_secs(1);
246 let after_two_secs = now + Duration::from_secs(2);
247 let atomic_time = AtomicSystemTime::new(now);
248
249 let mut result;
251 loop {
252 result =
253 atomic_time.compare_exchange_weak(now, after_one_sec, Ordering::SeqCst, Ordering::SeqCst);
254 if result.is_ok() {
255 break;
256 }
257 }
258 assert!(result.is_ok());
259 assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
260
261 let result =
263 atomic_time.compare_exchange_weak(now, after_two_secs, Ordering::SeqCst, Ordering::SeqCst);
264 assert!(result.is_err());
265 assert_eq!(result.unwrap_err(), after_one_sec);
266 }
267
268 #[test]
269 fn test_atomic_system_time_compare_exchange() {
270 let now = SystemTime::now();
271 let after_one_sec = now + Duration::from_secs(1);
272 let atomic_time = AtomicSystemTime::new(now);
273 let result =
274 atomic_time.compare_exchange(now, after_one_sec, Ordering::SeqCst, Ordering::SeqCst);
275 assert!(result.is_ok());
276 assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
277 }
278
279 #[test]
280 fn test_atomic_system_time_fetch_update() {
281 let now = SystemTime::now();
282 let atomic_time = AtomicSystemTime::new(now);
283
284 let result = atomic_time.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
286 Some(prev + Duration::from_secs(1))
287 });
288 assert!(result.is_ok());
289 assert_eq!(result.unwrap(), now);
290 assert_eq!(
291 atomic_time.load(Ordering::SeqCst),
292 now + Duration::from_secs(1)
293 );
294
295 let result = atomic_time.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None);
297 assert!(result.is_err());
298 assert_eq!(result.unwrap_err(), now + Duration::from_secs(1));
299 assert_eq!(
300 atomic_time.load(Ordering::SeqCst),
301 now + Duration::from_secs(1)
302 );
303 }
304
305 #[test]
306 #[cfg(feature = "std")]
307 fn test_atomic_system_time_thread_safety() {
308 use std::sync::Arc;
309 use std::thread;
310
311 let atomic_time = Arc::new(AtomicSystemTime::now());
312 let mut handles = vec![];
313
314 for _ in 0..4 {
315 let atomic_clone = atomic_time.clone();
316 let handle = thread::spawn(move || {
317 let current = atomic_clone.load(Ordering::SeqCst);
318 let new = current + Duration::from_secs(1);
319 atomic_clone.store(new, Ordering::SeqCst);
320 });
321 handles.push(handle);
322 }
323
324 for handle in handles {
325 handle.join().unwrap();
326 }
327
328 assert!(atomic_time.load(Ordering::SeqCst) > SystemTime::now());
331 }
332
333 #[cfg(feature = "serde")]
334 #[test]
335 fn test_atomic_system_time_serde() {
336 use serde::{Deserialize, Serialize};
337
338 #[derive(Serialize, Deserialize)]
339 struct Test {
340 time: AtomicSystemTime,
341 }
342
343 let now = SystemTime::now();
344 let test = Test {
345 time: AtomicSystemTime::new(now),
346 };
347 let serialized = serde_json::to_string(&test).unwrap();
348 let deserialized: Test = serde_json::from_str(&serialized).unwrap();
349 assert_eq!(deserialized.time.load(Ordering::SeqCst), now,);
350 }
351}