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 core::fmt::Debug for AtomicSystemTime {
11 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
12 f.debug_tuple("AtomicSystemTime")
13 .field(&self.load(Ordering::SeqCst))
14 .finish()
15 }
16}
17impl From<SystemTime> for AtomicSystemTime {
18 #[inline]
22 fn from(system_time: SystemTime) -> Self {
23 Self::new(system_time)
24 }
25}
26impl AtomicSystemTime {
27 pub fn now() -> Self {
36 Self::new(SystemTime::now())
37 }
38
39 pub fn new(system_time: SystemTime) -> Self {
45 Self(AtomicDuration::new(
46 system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
47 ))
48 }
49
50 pub fn load(&self, order: Ordering) -> SystemTime {
52 SystemTime::UNIX_EPOCH + self.0.load(order)
53 }
54
55 pub fn store(&self, system_time: SystemTime, order: Ordering) {
61 self.0.store(
62 system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
63 order,
64 )
65 }
66
67 pub fn swap(&self, system_time: SystemTime, order: Ordering) -> SystemTime {
73 SystemTime::UNIX_EPOCH
74 + self.0.swap(
75 system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
76 order,
77 )
78 }
79
80 pub fn compare_exchange(
87 &self,
88 current: SystemTime,
89 new: SystemTime,
90 success: Ordering,
91 failure: Ordering,
92 ) -> Result<SystemTime, SystemTime> {
93 match self.0.compare_exchange(
94 current.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
95 new.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
96 success,
97 failure,
98 ) {
99 Ok(duration) => Ok(SystemTime::UNIX_EPOCH + duration),
100 Err(duration) => Err(SystemTime::UNIX_EPOCH + duration),
101 }
102 }
103
104 pub fn compare_exchange_weak(
111 &self,
112 current: SystemTime,
113 new: SystemTime,
114 success: Ordering,
115 failure: Ordering,
116 ) -> Result<SystemTime, SystemTime> {
117 match self.0.compare_exchange_weak(
118 current.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
119 new.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
120 success,
121 failure,
122 ) {
123 Ok(duration) => Ok(SystemTime::UNIX_EPOCH + duration),
124 Err(duration) => Err(SystemTime::UNIX_EPOCH + duration),
125 }
126 }
127
128 pub fn fetch_update<F>(
167 &self,
168 set_order: Ordering,
169 fetch_order: Ordering,
170 mut f: F,
171 ) -> Result<SystemTime, SystemTime>
172 where
173 F: FnMut(SystemTime) -> Option<SystemTime>,
174 {
175 self
176 .0
177 .fetch_update(set_order, fetch_order, |duration| {
178 f(SystemTime::UNIX_EPOCH + duration)
179 .map(|system_time| system_time.duration_since(SystemTime::UNIX_EPOCH).unwrap())
180 })
181 .map(|duration| SystemTime::UNIX_EPOCH + duration)
182 .map_err(|duration| SystemTime::UNIX_EPOCH + duration)
183 }
184
185 #[inline]
197 pub fn is_lock_free() -> bool {
198 AtomicDuration::is_lock_free()
199 }
200
201 #[inline]
206 pub fn into_inner(self) -> SystemTime {
207 SystemTime::UNIX_EPOCH + self.0.into_inner()
208 }
209}
210
211#[cfg(feature = "serde")]
212const _: () = {
213 use serde::{Deserialize, Serialize};
214
215 impl Serialize for AtomicSystemTime {
216 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
217 self.load(Ordering::SeqCst).serialize(serializer)
218 }
219 }
220
221 impl<'de> Deserialize<'de> for AtomicSystemTime {
222 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
223 Ok(Self::new(SystemTime::deserialize(deserializer)?))
224 }
225 }
226};
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231 use std::time::Duration;
232
233 #[test]
234 fn test_atomic_system_time_now() {
235 let atomic_time = AtomicSystemTime::now();
236 assert_ne!(atomic_time.load(Ordering::SeqCst), SystemTime::UNIX_EPOCH);
239 }
240
241 #[test]
242 fn test_atomic_system_time_new_and_load() {
243 let now = SystemTime::now();
244 let atomic_time = AtomicSystemTime::new(now);
245 assert_eq!(atomic_time.load(Ordering::SeqCst), now);
246 }
247
248 #[test]
249 fn test_atomic_system_time_store_and_load() {
250 let now = SystemTime::now();
251 let after_one_sec = now + Duration::from_secs(1);
252 let atomic_time = AtomicSystemTime::new(now);
253 atomic_time.store(after_one_sec, Ordering::SeqCst);
254 assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
255 }
256
257 #[test]
258 fn test_atomic_system_time_swap() {
259 let now = SystemTime::now();
260 let after_one_sec = now + Duration::from_secs(1);
261 let atomic_time = AtomicSystemTime::new(now);
262 let prev_time = atomic_time.swap(after_one_sec, Ordering::SeqCst);
263 assert_eq!(prev_time, now);
264 assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
265 }
266
267 #[test]
268 fn test_atomic_system_time_compare_exchange_weak() {
269 let now = SystemTime::now();
270 let after_one_sec = now + Duration::from_secs(1);
271 let after_two_secs = now + Duration::from_secs(2);
272 let atomic_time = AtomicSystemTime::new(now);
273
274 let mut result;
276 loop {
277 result =
278 atomic_time.compare_exchange_weak(now, after_one_sec, Ordering::SeqCst, Ordering::SeqCst);
279 if result.is_ok() {
280 break;
281 }
282 }
283 assert!(result.is_ok());
284 assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
285
286 let result =
288 atomic_time.compare_exchange_weak(now, after_two_secs, Ordering::SeqCst, Ordering::SeqCst);
289 assert!(result.is_err());
290 assert_eq!(result.unwrap_err(), after_one_sec);
291 }
292
293 #[test]
294 fn test_atomic_system_time_compare_exchange() {
295 let now = SystemTime::now();
296 let after_one_sec = now + Duration::from_secs(1);
297 let atomic_time = AtomicSystemTime::new(now);
298 let result =
299 atomic_time.compare_exchange(now, after_one_sec, Ordering::SeqCst, Ordering::SeqCst);
300 assert!(result.is_ok());
301 assert_eq!(atomic_time.load(Ordering::SeqCst), after_one_sec);
302 }
303
304 #[test]
305 fn test_atomic_system_time_fetch_update() {
306 let now = SystemTime::now();
307 let atomic_time = AtomicSystemTime::new(now);
308
309 let result = atomic_time.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
311 Some(prev + Duration::from_secs(1))
312 });
313 assert!(result.is_ok());
314 assert_eq!(result.unwrap(), now);
315 assert_eq!(
316 atomic_time.load(Ordering::SeqCst),
317 now + Duration::from_secs(1)
318 );
319
320 let result = atomic_time.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None);
322 assert!(result.is_err());
323 assert_eq!(result.unwrap_err(), now + Duration::from_secs(1));
324 assert_eq!(
325 atomic_time.load(Ordering::SeqCst),
326 now + Duration::from_secs(1)
327 );
328 }
329
330 #[test]
331 #[cfg(feature = "std")]
332 fn test_atomic_system_time_thread_safety() {
333 use std::sync::Arc;
334 use std::thread;
335
336 let atomic_time = Arc::new(AtomicSystemTime::now());
337 let mut handles = vec![];
338
339 for _ in 0..4 {
340 let atomic_clone = atomic_time.clone();
341 let handle = thread::spawn(move || {
342 let current = atomic_clone.load(Ordering::SeqCst);
343 let new = current + Duration::from_secs(1);
344 atomic_clone.store(new, Ordering::SeqCst);
345 });
346 handles.push(handle);
347 }
348
349 for handle in handles {
350 handle.join().unwrap();
351 }
352
353 assert!(atomic_time.load(Ordering::SeqCst) > SystemTime::now());
356 }
357
358 #[cfg(feature = "serde")]
359 #[test]
360 fn test_atomic_system_time_serde() {
361 use serde::{Deserialize, Serialize};
362
363 #[derive(Serialize, Deserialize)]
364 struct Test {
365 time: AtomicSystemTime,
366 }
367
368 let now = SystemTime::now();
369 let test = Test {
370 time: AtomicSystemTime::new(now),
371 };
372 let serialized = serde_json::to_string(&test).unwrap();
373 let deserialized: Test = serde_json::from_str(&serialized).unwrap();
374 assert_eq!(deserialized.time.load(Ordering::SeqCst), now,);
375 }
376}