atomic_time/
option_instant.rs1use std::time::Instant;
2
3use super::*;
4
5#[repr(transparent)]
7pub struct AtomicOptionInstant(AtomicOptionDuration);
8
9impl Default for AtomicOptionInstant {
10 #[inline]
12 fn default() -> Self {
13 Self::none()
14 }
15}
16
17impl AtomicOptionInstant {
18 #[inline]
29 pub const fn none() -> Self {
30 Self(AtomicOptionDuration::new(None))
31 }
32
33 pub fn now() -> Self {
42 Self::new(Some(Instant::now()))
43 }
44
45 pub fn new(instant: Option<Instant>) -> Self {
47 Self(AtomicOptionDuration::new(
48 instant.map(encode_instant_to_duration),
49 ))
50 }
51
52 pub fn load(&self, order: Ordering) -> Option<Instant> {
54 self.0.load(order).map(decode_instant_from_duration)
55 }
56
57 pub fn store(&self, instant: Option<Instant>, order: Ordering) {
59 self.0.store(instant.map(encode_instant_to_duration), order)
60 }
61
62 pub fn swap(&self, instant: Option<Instant>, order: Ordering) -> Option<Instant> {
64 self
65 .0
66 .swap(instant.map(encode_instant_to_duration), order)
67 .map(decode_instant_from_duration)
68 }
69
70 pub fn compare_exchange(
73 &self,
74 current: Option<Instant>,
75 new: Option<Instant>,
76 success: Ordering,
77 failure: Ordering,
78 ) -> Result<Option<Instant>, Option<Instant>> {
79 match self.0.compare_exchange(
80 current.map(encode_instant_to_duration),
81 new.map(encode_instant_to_duration),
82 success,
83 failure,
84 ) {
85 Ok(duration) => Ok(duration.map(decode_instant_from_duration)),
86 Err(duration) => Err(duration.map(decode_instant_from_duration)),
87 }
88 }
89
90 pub fn compare_exchange_weak(
93 &self,
94 current: Option<Instant>,
95 new: Option<Instant>,
96 success: Ordering,
97 failure: Ordering,
98 ) -> Result<Option<Instant>, Option<Instant>> {
99 match self.0.compare_exchange_weak(
100 current.map(encode_instant_to_duration),
101 new.map(encode_instant_to_duration),
102 success,
103 failure,
104 ) {
105 Ok(duration) => Ok(duration.map(decode_instant_from_duration)),
106 Err(duration) => Err(duration.map(decode_instant_from_duration)),
107 }
108 }
109
110 pub fn fetch_update<F>(
146 &self,
147 set_order: Ordering,
148 fetch_order: Ordering,
149 mut f: F,
150 ) -> Result<Option<Instant>, Option<Instant>>
151 where
152 F: FnMut(Option<Instant>) -> Option<Option<Instant>>,
153 {
154 self
155 .0
156 .fetch_update(set_order, fetch_order, |duration| {
157 f(duration.map(decode_instant_from_duration))
158 .map(|system_time| system_time.map(encode_instant_to_duration))
159 })
160 .map(|duration| duration.map(decode_instant_from_duration))
161 .map_err(|duration| duration.map(decode_instant_from_duration))
162 }
163
164 #[inline]
176 pub fn is_lock_free() -> bool {
177 AtomicU128::is_lock_free()
178 }
179}
180
181#[cfg(feature = "serde")]
182const _: () = {
183 use core::time::Duration;
184 use serde::{Deserialize, Serialize};
185
186 impl Serialize for AtomicOptionInstant {
187 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
188 self.0.load(Ordering::SeqCst).serialize(serializer)
189 }
190 }
191
192 impl<'de> Deserialize<'de> for AtomicOptionInstant {
193 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
194 Ok(Self::new(
195 Option::<Duration>::deserialize(deserializer)?.map(decode_instant_from_duration),
196 ))
197 }
198 }
199};
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204 use std::time::Duration;
205
206 #[test]
207 fn test_atomic_option_instant_none() {
208 let atomic_instant = AtomicOptionInstant::none();
209 assert_eq!(atomic_instant.load(Ordering::SeqCst), None);
210 }
211
212 #[test]
213 fn test_atomic_option_instant_now() {
214 let atomic_instant = AtomicOptionInstant::now();
215 let now = Instant::now();
216 if let Some(loaded_instant) = atomic_instant.load(Ordering::SeqCst) {
217 assert!(loaded_instant <= now);
218 assert!(loaded_instant >= now - Duration::from_secs(1));
219 } else {
220 panic!("AtomicOptionInstant::now() should not be None");
221 }
222 }
223
224 #[test]
225 fn test_atomic_option_instant_new_and_load() {
226 let now = Some(Instant::now());
227 let atomic_instant = AtomicOptionInstant::new(now);
228 assert_eq!(atomic_instant.load(Ordering::SeqCst), now);
229 }
230
231 #[test]
232 fn test_atomic_option_instant_store_and_load() {
233 let now = Some(Instant::now());
234 let after_one_sec = now.map(|t| t + Duration::from_secs(1));
235 let atomic_instant = AtomicOptionInstant::new(now);
236 atomic_instant.store(after_one_sec, Ordering::SeqCst);
237 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
238 }
239
240 #[test]
241 fn test_atomic_option_instant_swap() {
242 let now = Some(Instant::now());
243 let after_one_sec = now.map(|t| t + Duration::from_secs(1));
244 let atomic_instant = AtomicOptionInstant::new(now);
245 let prev_instant = atomic_instant.swap(after_one_sec, Ordering::SeqCst);
246 assert_eq!(prev_instant, now);
247 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
248 }
249
250 #[test]
251 fn test_atomic_option_instant_compare_exchange() {
252 let now = Some(Instant::now());
253 let after_one_sec = now.map(|t| t + Duration::from_secs(1));
254 let atomic_instant = AtomicOptionInstant::new(now);
255 let result =
256 atomic_instant.compare_exchange(now, after_one_sec, Ordering::SeqCst, Ordering::SeqCst);
257 assert!(result.is_ok());
258 assert_eq!(atomic_instant.load(Ordering::SeqCst), after_one_sec);
259 }
260
261 #[test]
262 fn test_atomic_option_instant_compare_exchange_weak() {
263 let now = Some(Instant::now());
264 let after_one_sec = now.map(|t| t + Duration::from_secs(1));
265 let atomic_instant = AtomicOptionInstant::new(now);
266
267 let mut result;
268 loop {
269 result = atomic_instant.compare_exchange_weak(
270 now,
271 after_one_sec,
272 Ordering::SeqCst,
273 Ordering::SeqCst,
274 );
275 if result.is_ok() {
276 break;
277 }
278 }
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_fetch_update() {
285 let now = Some(Instant::now());
286 let atomic_instant = AtomicOptionInstant::new(now);
287
288 let result = atomic_instant.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
289 Some(prev.map(|t| t + Duration::from_secs(1)))
290 });
291 assert!(result.is_ok());
292 assert_eq!(result.unwrap(), now);
293 assert_eq!(
294 atomic_instant.load(Ordering::SeqCst),
295 now.map(|t| t + Duration::from_secs(1))
296 );
297 }
298
299 #[test]
300 fn test_atomic_option_instant_thread_safety() {
301 use std::sync::Arc;
302 use std::thread;
303
304 let atomic_time = Arc::new(AtomicOptionInstant::now());
305 let mut handles = vec![];
306
307 for _ in 0..4 {
309 let atomic_clone = Arc::clone(&atomic_time);
310 let handle = thread::spawn(move || {
311 let current = atomic_clone.load(Ordering::SeqCst);
312 if let Some(current_time) = current {
313 let new_time = current_time + Duration::from_secs(1);
315 atomic_clone.store(Some(new_time), Ordering::SeqCst);
316 }
317 });
318 handles.push(handle);
319 }
320
321 for handle in handles {
323 handle.join().unwrap();
324 }
325
326 if let Some(updated_time) = atomic_time.load(Ordering::SeqCst) {
328 assert!(updated_time > Instant::now() - Duration::from_secs(4));
329 } else {
330 panic!("AtomicOptionInstant should not be None");
331 }
332 }
333
334 #[cfg(feature = "serde")]
335 #[test]
336 fn test_atomic_system_time_serde() {
337 use std::time::SystemTime;
338
339 use serde::{Deserialize, Serialize};
340
341 #[derive(Serialize, Deserialize)]
342 struct Test {
343 time: AtomicOptionSystemTime,
344 }
345
346 let now = SystemTime::now();
347 let test = Test {
348 time: AtomicOptionSystemTime::new(Some(now)),
349 };
350 let serialized = serde_json::to_string(&test).unwrap();
351 let deserialized: Test = serde_json::from_str(&serialized).unwrap();
352 assert_eq!(deserialized.time.load(Ordering::SeqCst), Some(now));
353 }
354}