atomic_time/
option_system_time.rs1use core::sync::atomic::Ordering;
2use std::time::SystemTime;
3
4use crate::AtomicOptionDuration;
5
6#[repr(transparent)]
8pub struct AtomicOptionSystemTime(AtomicOptionDuration);
9
10impl Default for AtomicOptionSystemTime {
11 #[inline]
13 fn default() -> Self {
14 Self::none()
15 }
16}
17
18impl AtomicOptionSystemTime {
19 #[inline]
30 pub const fn none() -> Self {
31 Self(AtomicOptionDuration::new(None))
32 }
33
34 pub fn now() -> Self {
43 Self::new(Some(SystemTime::now()))
44 }
45
46 pub fn new(system_time: Option<SystemTime>) -> Self {
52 Self(AtomicOptionDuration::new(
53 system_time.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
54 ))
55 }
56
57 pub fn load(&self, order: Ordering) -> Option<SystemTime> {
59 self.0.load(order).map(|val| SystemTime::UNIX_EPOCH + val)
60 }
61
62 pub fn store(&self, system_time: Option<SystemTime>, order: Ordering) {
68 self.0.store(
69 system_time.map(|val| val.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
70 order,
71 )
72 }
73
74 pub fn swap(&self, system_time: Option<SystemTime>, order: Ordering) -> Option<SystemTime> {
80 self
81 .0
82 .swap(
83 system_time.map(|val| val.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
84 order,
85 )
86 .map(|val| SystemTime::UNIX_EPOCH + val)
87 }
88
89 pub fn compare_exchange(
96 &self,
97 current: Option<SystemTime>,
98 new: Option<SystemTime>,
99 success: Ordering,
100 failure: Ordering,
101 ) -> Result<Option<SystemTime>, Option<SystemTime>> {
102 match self.0.compare_exchange(
103 current.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
104 new.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
105 success,
106 failure,
107 ) {
108 Ok(duration) => Ok(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
109 Err(duration) => Err(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
110 }
111 }
112
113 pub fn compare_exchange_weak(
120 &self,
121 current: Option<SystemTime>,
122 new: Option<SystemTime>,
123 success: Ordering,
124 failure: Ordering,
125 ) -> Result<Option<SystemTime>, Option<SystemTime>> {
126 match self.0.compare_exchange_weak(
127 current.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
128 new.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
129 success,
130 failure,
131 ) {
132 Ok(duration) => Ok(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
133 Err(duration) => Err(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
134 }
135 }
136
137 pub fn fetch_update<F>(
177 &self,
178 set_order: Ordering,
179 fetch_order: Ordering,
180 mut f: F,
181 ) -> Result<Option<SystemTime>, Option<SystemTime>>
182 where
183 F: FnMut(Option<SystemTime>) -> Option<Option<SystemTime>>,
184 {
185 self
186 .0
187 .fetch_update(set_order, fetch_order, |duration| {
188 f(duration.map(|d| SystemTime::UNIX_EPOCH + d))
189 .map(|system_time| system_time.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()))
190 })
191 .map(|duration| duration.map(|d| SystemTime::UNIX_EPOCH + d))
192 .map_err(|duration| duration.map(|d| SystemTime::UNIX_EPOCH + d))
193 }
194
195 #[inline]
207 pub fn is_lock_free() -> bool {
208 AtomicOptionDuration::is_lock_free()
209 }
210}
211
212#[cfg(feature = "serde")]
213const _: () = {
214 use serde::{Deserialize, Serialize};
215
216 impl Serialize for AtomicOptionSystemTime {
217 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
218 self.load(Ordering::SeqCst).serialize(serializer)
219 }
220 }
221
222 impl<'de> Deserialize<'de> for AtomicOptionSystemTime {
223 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
224 Ok(Self::new(Option::<SystemTime>::deserialize(deserializer)?))
225 }
226 }
227};
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232 use std::time::Duration;
233
234 #[test]
235 fn test_atomic_option_system_time_now() {
236 let atomic_time = AtomicOptionSystemTime::now();
237 assert!(atomic_time.load(Ordering::SeqCst).is_some());
239 }
240
241 #[test]
242 fn test_atomic_option_system_time_none() {
243 let atomic_time = AtomicOptionSystemTime::none();
244 assert_eq!(atomic_time.load(Ordering::SeqCst), None);
245 }
246
247 #[test]
248 fn test_atomic_option_system_time_new_and_load() {
249 let now = SystemTime::now();
250 let atomic_time = AtomicOptionSystemTime::new(Some(now));
251 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(now));
252 }
253
254 #[test]
255 fn test_atomic_option_system_time_store_and_load() {
256 let now = SystemTime::now();
257 let after_one_sec = now + Duration::from_secs(1);
258 let atomic_time = AtomicOptionSystemTime::new(Some(now));
259 atomic_time.store(Some(after_one_sec), Ordering::SeqCst);
260 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
261 }
262
263 #[test]
264 fn test_atomic_option_system_time_swap() {
265 let now = SystemTime::now();
266 let after_one_sec = now + Duration::from_secs(1);
267 let atomic_time = AtomicOptionSystemTime::new(Some(now));
268 let prev_time = atomic_time.swap(Some(after_one_sec), Ordering::SeqCst);
269 assert_eq!(prev_time, Some(now));
270 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
271 }
272
273 #[test]
274 fn test_atomic_option_system_time_compare_exchange() {
275 let now = SystemTime::now();
276 let after_one_sec = now + Duration::from_secs(1);
277 let atomic_time = AtomicOptionSystemTime::new(Some(now));
278 let result = atomic_time.compare_exchange(
279 Some(now),
280 Some(after_one_sec),
281 Ordering::SeqCst,
282 Ordering::SeqCst,
283 );
284 assert!(result.is_ok());
285 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
286 }
287
288 #[test]
289 fn test_atomic_option_system_time_compare_exchange_weak() {
290 let now = SystemTime::now();
291 let after_one_sec = now + Duration::from_secs(1);
292 let atomic_time = AtomicOptionSystemTime::new(Some(now));
293
294 let mut result;
295 loop {
296 result = atomic_time.compare_exchange_weak(
297 Some(now),
298 Some(after_one_sec),
299 Ordering::SeqCst,
300 Ordering::SeqCst,
301 );
302 if result.is_ok() {
303 break;
304 }
305 }
306 assert!(result.is_ok());
307 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
308 }
309
310 #[test]
311 fn test_atomic_option_system_time_fetch_update() {
312 let now = SystemTime::now();
313 let atomic_time = AtomicOptionSystemTime::new(Some(now));
314
315 let result = atomic_time.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
316 Some(prev.map(|val| val + Duration::from_secs(1)))
317 });
318 assert!(result.is_ok());
319 assert_eq!(result.unwrap(), Some(now));
320 assert_eq!(
321 atomic_time.load(Ordering::SeqCst),
322 Some(now + Duration::from_secs(1))
323 );
324 }
325
326 #[test]
327 fn test_atomic_option_system_time_thread_safety() {
328 use std::sync::Arc;
329 use std::thread;
330
331 let atomic_time = Arc::new(AtomicOptionSystemTime::now());
332 let mut handles = vec![];
333
334 for _ in 0..4 {
336 let atomic_clone = Arc::clone(&atomic_time);
337 let handle = thread::spawn(move || {
338 let current = atomic_clone.load(Ordering::SeqCst);
339 if let Some(current_time) = current {
340 let new_time = current_time + Duration::from_secs(1);
342 atomic_clone.store(Some(new_time), Ordering::SeqCst);
343 }
344 });
345 handles.push(handle);
346 }
347
348 for handle in handles {
350 handle.join().unwrap();
351 }
352
353 if let Some(updated_time) = atomic_time.load(Ordering::SeqCst) {
355 assert!(updated_time > SystemTime::now() - Duration::from_secs(4));
356 } else {
357 panic!("AtomicOptionSystemTime should not be None");
358 }
359 }
360
361 #[cfg(feature = "serde")]
362 #[test]
363 fn test_atomic_system_time_serde() {
364 use serde::{Deserialize, Serialize};
365
366 #[derive(Serialize, Deserialize)]
367 struct Test {
368 time: AtomicOptionSystemTime,
369 }
370
371 let now = SystemTime::now();
372 let test = Test {
373 time: AtomicOptionSystemTime::new(Some(now)),
374 };
375 let serialized = serde_json::to_string(&test).unwrap();
376 let deserialized: Test = serde_json::from_str(&serialized).unwrap();
377 assert_eq!(deserialized.time.load(Ordering::SeqCst), Some(now));
378 }
379}