atomic_time/
option_instant.rs1use std::time::Instant;
2
3use super::*;
4
5#[repr(transparent)]
7pub struct AtomicOptionInstant(AtomicOptionDuration);
8
9impl core::fmt::Debug for AtomicOptionInstant {
10 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
11 f.debug_tuple("AtomicOptionInstant")
12 .field(&self.load(Ordering::SeqCst))
13 .finish()
14 }
15}
16impl Default for AtomicOptionInstant {
17 #[inline]
19 fn default() -> Self {
20 Self::none()
21 }
22}
23impl From<Option<Instant>> for AtomicOptionInstant {
24 #[inline]
25 fn from(instant: Option<Instant>) -> Self {
26 Self::new(instant)
27 }
28}
29
30impl AtomicOptionInstant {
31 #[inline]
42 pub const fn none() -> Self {
43 Self(AtomicOptionDuration::new(None))
44 }
45
46 pub fn now() -> Self {
55 Self::new(Some(Instant::now()))
56 }
57
58 pub fn new(instant: Option<Instant>) -> Self {
60 Self(AtomicOptionDuration::new(
61 instant.map(encode_instant_to_duration),
62 ))
63 }
64
65 pub fn load(&self, order: Ordering) -> Option<Instant> {
67 self.0.load(order).map(decode_instant_from_duration)
68 }
69
70 pub fn store(&self, instant: Option<Instant>, order: Ordering) {
72 self.0.store(instant.map(encode_instant_to_duration), order)
73 }
74
75 pub fn swap(&self, instant: Option<Instant>, order: Ordering) -> Option<Instant> {
77 self
78 .0
79 .swap(instant.map(encode_instant_to_duration), order)
80 .map(decode_instant_from_duration)
81 }
82
83 pub fn compare_exchange(
86 &self,
87 current: Option<Instant>,
88 new: Option<Instant>,
89 success: Ordering,
90 failure: Ordering,
91 ) -> Result<Option<Instant>, Option<Instant>> {
92 match self.0.compare_exchange(
93 current.map(encode_instant_to_duration),
94 new.map(encode_instant_to_duration),
95 success,
96 failure,
97 ) {
98 Ok(duration) => Ok(duration.map(decode_instant_from_duration)),
99 Err(duration) => Err(duration.map(decode_instant_from_duration)),
100 }
101 }
102
103 pub fn compare_exchange_weak(
106 &self,
107 current: Option<Instant>,
108 new: Option<Instant>,
109 success: Ordering,
110 failure: Ordering,
111 ) -> Result<Option<Instant>, Option<Instant>> {
112 match self.0.compare_exchange_weak(
113 current.map(encode_instant_to_duration),
114 new.map(encode_instant_to_duration),
115 success,
116 failure,
117 ) {
118 Ok(duration) => Ok(duration.map(decode_instant_from_duration)),
119 Err(duration) => Err(duration.map(decode_instant_from_duration)),
120 }
121 }
122
123 pub fn fetch_update<F>(
159 &self,
160 set_order: Ordering,
161 fetch_order: Ordering,
162 mut f: F,
163 ) -> Result<Option<Instant>, Option<Instant>>
164 where
165 F: FnMut(Option<Instant>) -> Option<Option<Instant>>,
166 {
167 self
168 .0
169 .fetch_update(set_order, fetch_order, |duration| {
170 f(duration.map(decode_instant_from_duration))
171 .map(|system_time| system_time.map(encode_instant_to_duration))
172 })
173 .map(|duration| duration.map(decode_instant_from_duration))
174 .map_err(|duration| duration.map(decode_instant_from_duration))
175 }
176
177 #[inline]
189 pub fn is_lock_free() -> bool {
190 AtomicU128::is_lock_free()
191 }
192
193 #[inline]
198 pub fn into_inner(self) -> Option<Instant> {
199 self.0.into_inner().map(decode_instant_from_duration)
200 }
201}
202
203#[cfg(feature = "serde")]
204const _: () = {
205 use core::time::Duration;
206 use serde::{Deserialize, Serialize};
207
208 impl Serialize for AtomicOptionInstant {
209 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
210 self.0.load(Ordering::SeqCst).serialize(serializer)
211 }
212 }
213
214 impl<'de> Deserialize<'de> for AtomicOptionInstant {
215 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
216 Ok(Self::new(
217 Option::<Duration>::deserialize(deserializer)?.map(decode_instant_from_duration),
218 ))
219 }
220 }
221};
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226 use std::time::Duration;
227
228 #[test]
229 fn test_atomic_option_instant_none() {
230 let atomic_instant = AtomicOptionInstant::none();
231 assert_eq!(atomic_instant.load(Ordering::SeqCst), None);
232 }
233
234 #[test]
235 fn test_atomic_option_instant_now() {
236 let atomic_instant = AtomicOptionInstant::now();
237 let now = Instant::now();
238 if let Some(loaded_instant) = atomic_instant.load(Ordering::SeqCst) {
239 assert!(loaded_instant <= now);
240 assert!(loaded_instant >= now - Duration::from_secs(1));
241 } else {
242 panic!("AtomicOptionInstant::now() should not be None");
243 }
244 }
245
246 #[test]
247 fn test_atomic_option_instant_new_and_load() {
248 let now = Some(Instant::now());
249 let atomic_instant = AtomicOptionInstant::new(now);
250 assert_eq!(atomic_instant.load(Ordering::SeqCst), now);
251 }
252
253 #[test]
254 fn test_atomic_option_instant_store_and_load() {
255 let now = Some(Instant::now());
256 let after_one_sec = now.map(|t| t + Duration::from_secs(1));
257 let atomic_instant = AtomicOptionInstant::new(now);
258 atomic_instant.store(after_one_sec, Ordering::SeqCst);
259 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
260 }
261
262 #[test]
263 fn test_atomic_option_instant_swap() {
264 let now = Some(Instant::now());
265 let after_one_sec = now.map(|t| t + Duration::from_secs(1));
266 let atomic_instant = AtomicOptionInstant::new(now);
267 let prev_instant = atomic_instant.swap(after_one_sec, Ordering::SeqCst);
268 assert_eq!(prev_instant, now);
269 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
270 }
271
272 #[test]
273 fn test_atomic_option_instant_compare_exchange() {
274 let now = Some(Instant::now());
275 let after_one_sec = now.map(|t| t + Duration::from_secs(1));
276 let atomic_instant = AtomicOptionInstant::new(now);
277 let result =
278 atomic_instant.compare_exchange(now, after_one_sec, Ordering::SeqCst, Ordering::SeqCst);
279 assert!(result.is_ok());
280 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
281 }
282
283 #[test]
284 fn test_atomic_option_instant_compare_exchange_weak() {
285 let now = Some(Instant::now());
286 let after_one_sec = now.map(|t| t + Duration::from_secs(1));
287 let atomic_instant = AtomicOptionInstant::new(now);
288
289 let mut result;
290 loop {
291 result = atomic_instant.compare_exchange_weak(
292 now,
293 after_one_sec,
294 Ordering::SeqCst,
295 Ordering::SeqCst,
296 );
297 if result.is_ok() {
298 break;
299 }
300 }
301 assert!(result.is_ok());
302 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
303 }
304
305 #[test]
306 fn test_atomic_option_instant_fetch_update() {
307 let now = Some(Instant::now());
308 let atomic_instant = AtomicOptionInstant::new(now);
309
310 let result = atomic_instant.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
311 Some(prev.map(|t| t + Duration::from_secs(1)))
312 });
313 assert!(result.is_ok());
314 assert_eq!(result.unwrap(), now);
315 assert_eq!(
316 atomic_instant.load(Ordering::SeqCst),
317 now.map(|t| t + Duration::from_secs(1))
318 );
319 }
320
321 #[test]
322 fn test_atomic_option_instant_thread_safety() {
323 use std::sync::Arc;
324 use std::thread;
325
326 let atomic_time = Arc::new(AtomicOptionInstant::now());
327 let mut handles = vec![];
328
329 for _ in 0..4 {
331 let atomic_clone = Arc::clone(&atomic_time);
332 let handle = thread::spawn(move || {
333 let current = atomic_clone.load(Ordering::SeqCst);
334 if let Some(current_time) = current {
335 let new_time = current_time + Duration::from_secs(1);
337 atomic_clone.store(Some(new_time), Ordering::SeqCst);
338 }
339 });
340 handles.push(handle);
341 }
342
343 for handle in handles {
345 handle.join().unwrap();
346 }
347
348 if let Some(updated_time) = atomic_time.load(Ordering::SeqCst) {
350 assert!(updated_time > Instant::now() - Duration::from_secs(4));
351 } else {
352 panic!("AtomicOptionInstant should not be None");
353 }
354 }
355
356 #[cfg(feature = "serde")]
357 #[test]
358 fn test_atomic_option_instant_serde() {
359 use serde::{Deserialize, Serialize};
360
361 #[derive(Serialize, Deserialize)]
362 struct Test {
363 time: AtomicOptionInstant,
364 }
365
366 let now = Instant::now();
367 let test = Test {
368 time: AtomicOptionInstant::new(Some(now)),
369 };
370 let serialized = serde_json::to_string(&test).unwrap();
371 let deserialized: Test = serde_json::from_str(&serialized).unwrap();
372 assert_eq!(deserialized.time.load(Ordering::SeqCst), Some(now));
373 }
374}