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 core::fmt::Debug for AtomicOptionSystemTime {
11 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
12 f.debug_tuple("AtomicOptionSystemTime")
13 .field(&self.load(Ordering::SeqCst))
14 .finish()
15 }
16}
17impl Default for AtomicOptionSystemTime {
18 #[inline]
20 fn default() -> Self {
21 Self::none()
22 }
23}
24impl From<Option<SystemTime>> for AtomicOptionSystemTime {
25 #[inline]
29 fn from(system_time: Option<SystemTime>) -> Self {
30 Self::new(system_time)
31 }
32}
33
34impl AtomicOptionSystemTime {
35 #[inline]
46 pub const fn none() -> Self {
47 Self(AtomicOptionDuration::new(None))
48 }
49
50 pub fn now() -> Self {
59 Self::new(Some(SystemTime::now()))
60 }
61
62 pub fn new(system_time: Option<SystemTime>) -> Self {
68 Self(AtomicOptionDuration::new(
69 system_time.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
70 ))
71 }
72
73 pub fn load(&self, order: Ordering) -> Option<SystemTime> {
75 self.0.load(order).map(|val| SystemTime::UNIX_EPOCH + val)
76 }
77
78 pub fn store(&self, system_time: Option<SystemTime>, order: Ordering) {
84 self.0.store(
85 system_time.map(|val| val.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
86 order,
87 )
88 }
89
90 pub fn swap(&self, system_time: Option<SystemTime>, order: Ordering) -> Option<SystemTime> {
96 self
97 .0
98 .swap(
99 system_time.map(|val| val.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
100 order,
101 )
102 .map(|val| SystemTime::UNIX_EPOCH + val)
103 }
104
105 pub fn compare_exchange(
112 &self,
113 current: Option<SystemTime>,
114 new: Option<SystemTime>,
115 success: Ordering,
116 failure: Ordering,
117 ) -> Result<Option<SystemTime>, Option<SystemTime>> {
118 match self.0.compare_exchange(
119 current.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
120 new.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
121 success,
122 failure,
123 ) {
124 Ok(duration) => Ok(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
125 Err(duration) => Err(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
126 }
127 }
128
129 pub fn compare_exchange_weak(
136 &self,
137 current: Option<SystemTime>,
138 new: Option<SystemTime>,
139 success: Ordering,
140 failure: Ordering,
141 ) -> Result<Option<SystemTime>, Option<SystemTime>> {
142 match self.0.compare_exchange_weak(
143 current.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
144 new.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()),
145 success,
146 failure,
147 ) {
148 Ok(duration) => Ok(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
149 Err(duration) => Err(duration.map(|d| SystemTime::UNIX_EPOCH + d)),
150 }
151 }
152
153 pub fn fetch_update<F>(
193 &self,
194 set_order: Ordering,
195 fetch_order: Ordering,
196 mut f: F,
197 ) -> Result<Option<SystemTime>, Option<SystemTime>>
198 where
199 F: FnMut(Option<SystemTime>) -> Option<Option<SystemTime>>,
200 {
201 self
202 .0
203 .fetch_update(set_order, fetch_order, |duration| {
204 f(duration.map(|d| SystemTime::UNIX_EPOCH + d))
205 .map(|system_time| system_time.map(|d| d.duration_since(SystemTime::UNIX_EPOCH).unwrap()))
206 })
207 .map(|duration| duration.map(|d| SystemTime::UNIX_EPOCH + d))
208 .map_err(|duration| duration.map(|d| SystemTime::UNIX_EPOCH + d))
209 }
210
211 #[inline]
223 pub fn is_lock_free() -> bool {
224 AtomicOptionDuration::is_lock_free()
225 }
226
227 #[inline]
232 pub fn into_inner(self) -> Option<SystemTime> {
233 self.0.into_inner().map(|d| SystemTime::UNIX_EPOCH + d)
234 }
235}
236
237#[cfg(feature = "serde")]
238const _: () = {
239 use serde::{Deserialize, Serialize};
240
241 impl Serialize for AtomicOptionSystemTime {
242 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
243 self.load(Ordering::SeqCst).serialize(serializer)
244 }
245 }
246
247 impl<'de> Deserialize<'de> for AtomicOptionSystemTime {
248 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
249 Ok(Self::new(Option::<SystemTime>::deserialize(deserializer)?))
250 }
251 }
252};
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257 use std::time::Duration;
258
259 #[test]
260 fn test_atomic_option_system_time_now() {
261 let atomic_time = AtomicOptionSystemTime::now();
262 assert!(atomic_time.load(Ordering::SeqCst).is_some());
264 }
265
266 #[test]
267 fn test_atomic_option_system_time_none() {
268 let atomic_time = AtomicOptionSystemTime::none();
269 assert_eq!(atomic_time.load(Ordering::SeqCst), None);
270 }
271
272 #[test]
273 fn test_atomic_option_system_time_new_and_load() {
274 let now = SystemTime::now();
275 let atomic_time = AtomicOptionSystemTime::new(Some(now));
276 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(now));
277 }
278
279 #[test]
280 fn test_atomic_option_system_time_store_and_load() {
281 let now = SystemTime::now();
282 let after_one_sec = now + Duration::from_secs(1);
283 let atomic_time = AtomicOptionSystemTime::new(Some(now));
284 atomic_time.store(Some(after_one_sec), Ordering::SeqCst);
285 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
286 }
287
288 #[test]
289 fn test_atomic_option_system_time_swap() {
290 let now = SystemTime::now();
291 let after_one_sec = now + Duration::from_secs(1);
292 let atomic_time = AtomicOptionSystemTime::new(Some(now));
293 let prev_time = atomic_time.swap(Some(after_one_sec), Ordering::SeqCst);
294 assert_eq!(prev_time, Some(now));
295 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
296 }
297
298 #[test]
299 fn test_atomic_option_system_time_compare_exchange() {
300 let now = SystemTime::now();
301 let after_one_sec = now + Duration::from_secs(1);
302 let atomic_time = AtomicOptionSystemTime::new(Some(now));
303 let result = atomic_time.compare_exchange(
304 Some(now),
305 Some(after_one_sec),
306 Ordering::SeqCst,
307 Ordering::SeqCst,
308 );
309 assert!(result.is_ok());
310 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
311 }
312
313 #[test]
314 fn test_atomic_option_system_time_compare_exchange_weak() {
315 let now = SystemTime::now();
316 let after_one_sec = now + Duration::from_secs(1);
317 let atomic_time = AtomicOptionSystemTime::new(Some(now));
318
319 let mut result;
320 loop {
321 result = atomic_time.compare_exchange_weak(
322 Some(now),
323 Some(after_one_sec),
324 Ordering::SeqCst,
325 Ordering::SeqCst,
326 );
327 if result.is_ok() {
328 break;
329 }
330 }
331 assert!(result.is_ok());
332 assert_eq!(atomic_time.load(Ordering::SeqCst), Some(after_one_sec));
333 }
334
335 #[test]
336 fn test_atomic_option_system_time_fetch_update() {
337 let now = SystemTime::now();
338 let atomic_time = AtomicOptionSystemTime::new(Some(now));
339
340 let result = atomic_time.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
341 Some(prev.map(|val| val + Duration::from_secs(1)))
342 });
343 assert!(result.is_ok());
344 assert_eq!(result.unwrap(), Some(now));
345 assert_eq!(
346 atomic_time.load(Ordering::SeqCst),
347 Some(now + Duration::from_secs(1))
348 );
349 }
350
351 #[test]
352 fn test_atomic_option_system_time_thread_safety() {
353 use std::sync::Arc;
354 use std::thread;
355
356 let atomic_time = Arc::new(AtomicOptionSystemTime::now());
357 let mut handles = vec![];
358
359 for _ in 0..4 {
361 let atomic_clone = Arc::clone(&atomic_time);
362 let handle = thread::spawn(move || {
363 let current = atomic_clone.load(Ordering::SeqCst);
364 if let Some(current_time) = current {
365 let new_time = current_time + Duration::from_secs(1);
367 atomic_clone.store(Some(new_time), Ordering::SeqCst);
368 }
369 });
370 handles.push(handle);
371 }
372
373 for handle in handles {
375 handle.join().unwrap();
376 }
377
378 if let Some(updated_time) = atomic_time.load(Ordering::SeqCst) {
380 assert!(updated_time > SystemTime::now() - Duration::from_secs(4));
381 } else {
382 panic!("AtomicOptionSystemTime should not be None");
383 }
384 }
385
386 #[cfg(feature = "serde")]
387 #[test]
388 fn test_atomic_system_time_serde() {
389 use serde::{Deserialize, Serialize};
390
391 #[derive(Serialize, Deserialize)]
392 struct Test {
393 time: AtomicOptionSystemTime,
394 }
395
396 let now = SystemTime::now();
397 let test = Test {
398 time: AtomicOptionSystemTime::new(Some(now)),
399 };
400 let serialized = serde_json::to_string(&test).unwrap();
401 let deserialized: Test = serde_json::from_str(&serialized).unwrap();
402 assert_eq!(deserialized.time.load(Ordering::SeqCst), Some(now));
403 }
404}