qubit_atomic/atomic/atomic_ref.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10
11//! # Atomic Reference
12//!
13//! Provides an easy-to-use atomic reference type with sensible default memory
14//! orderings. Uses `Arc<T>` for thread-safe reference counting.
15//!
16
17use arc_swap::{
18 ArcSwap,
19 Guard,
20};
21use std::fmt;
22use std::sync::Arc;
23
24/// Atomic reference type.
25///
26/// Provides easy-to-use atomic operations on references with automatic memory
27/// ordering selection. Uses `Arc<T>` for thread-safe reference counting.
28///
29/// # Implementation Details
30///
31/// This type is backed by `arc_swap::ArcSwap<T>`, which provides lock-free,
32/// memory-safe atomic replacement and loading of `Arc<T>` values without
33/// exposing raw-pointer lifetime hazards.
34///
35/// # Features
36///
37/// - Automatic memory ordering selection
38/// - Thread-safe reference counting via `Arc`
39/// - Functional update operations
40/// - Zero-cost abstraction with inline methods
41///
42/// # Example
43///
44/// ```rust
45/// use qubit_atomic::AtomicRef;
46/// use std::sync::Arc;
47///
48/// #[derive(Debug, Clone)]
49/// struct Config {
50/// timeout: u64,
51/// max_retries: u32,
52/// }
53///
54/// let config = Arc::new(Config {
55/// timeout: 1000,
56/// max_retries: 3,
57/// });
58///
59/// let atomic_config = AtomicRef::new(config);
60///
61/// // Update configuration
62/// let new_config = Arc::new(Config {
63/// timeout: 2000,
64/// max_retries: 5,
65/// });
66///
67/// let old_config = atomic_config.swap(new_config);
68/// assert_eq!(old_config.timeout, 1000);
69/// assert_eq!(atomic_config.load().timeout, 2000);
70/// ```
71///
72pub struct AtomicRef<T> {
73 /// Lock-free atomic storage for the current shared reference.
74 inner: ArcSwap<T>,
75}
76
77impl<T> AtomicRef<T> {
78 /// Creates a new atomic reference.
79 ///
80 /// # Parameters
81 ///
82 /// * `value` - The initial reference.
83 ///
84 /// # Returns
85 ///
86 /// An atomic reference initialized to `value`.
87 ///
88 /// # Example
89 ///
90 /// ```rust
91 /// use qubit_atomic::AtomicRef;
92 /// use std::sync::Arc;
93 ///
94 /// let data = Arc::new(42);
95 /// let atomic = AtomicRef::new(data);
96 /// assert_eq!(*atomic.load(), 42);
97 /// ```
98 #[inline]
99 pub fn new(value: Arc<T>) -> Self {
100 Self {
101 inner: ArcSwap::from(value),
102 }
103 }
104
105 /// Creates a new atomic reference from an owned value.
106 ///
107 /// This is a convenience constructor for callers that do not already have
108 /// an [`Arc<T>`]. It wraps `value` in [`Arc::new`] and then delegates to
109 /// [`new`](Self::new).
110 ///
111 /// # Parameters
112 ///
113 /// * `value` - The owned value to store as the initial reference.
114 ///
115 /// # Returns
116 ///
117 /// An atomic reference initialized to `Arc::new(value)`.
118 ///
119 /// # Example
120 ///
121 /// ```rust
122 /// use qubit_atomic::AtomicRef;
123 ///
124 /// let atomic = AtomicRef::from_value(42);
125 /// assert_eq!(*atomic.load(), 42);
126 /// ```
127 #[inline]
128 pub fn from_value(value: T) -> Self {
129 Self::new(Arc::new(value))
130 }
131
132 /// Gets the current reference.
133 ///
134 /// # Returns
135 ///
136 /// A cloned `Arc` pointing to the current value.
137 ///
138 /// # Example
139 ///
140 /// ```rust
141 /// use qubit_atomic::AtomicRef;
142 /// use std::sync::Arc;
143 ///
144 /// let atomic = AtomicRef::new(Arc::new(42));
145 /// let value = atomic.load();
146 /// assert_eq!(*value, 42);
147 /// ```
148 #[inline]
149 pub fn load(&self) -> Arc<T> {
150 self.inner.load_full()
151 }
152
153 /// Gets the current reference as an `ArcSwap` guard.
154 ///
155 /// This is useful for short-lived reads because it avoids cloning the
156 /// underlying [`Arc`] on the fast path. Use [`load`](Self::load) when the
157 /// caller needs an owned [`Arc<T>`] that can be stored or moved freely.
158 ///
159 /// # Returns
160 ///
161 /// A guard pointing to the current `Arc`.
162 ///
163 /// # Example
164 ///
165 /// ```rust
166 /// use qubit_atomic::AtomicRef;
167 /// use std::sync::Arc;
168 ///
169 /// let atomic = AtomicRef::new(Arc::new(42));
170 /// let guard = atomic.load_guard();
171 /// assert_eq!(**guard, 42);
172 /// ```
173 #[inline]
174 pub fn load_guard(&self) -> Guard<Arc<T>> {
175 self.inner.load()
176 }
177
178 /// Sets a new reference.
179 ///
180 /// # Parameters
181 ///
182 /// * `value` - The new reference to set.
183 ///
184 /// # Example
185 ///
186 /// ```rust
187 /// use qubit_atomic::AtomicRef;
188 /// use std::sync::Arc;
189 ///
190 /// let atomic = AtomicRef::new(Arc::new(42));
191 /// atomic.store(Arc::new(100));
192 /// assert_eq!(*atomic.load(), 100);
193 /// ```
194 #[inline]
195 pub fn store(&self, value: Arc<T>) {
196 self.inner.store(value);
197 }
198
199 /// Swaps the current reference with a new reference, returning the old
200 /// reference.
201 ///
202 /// # Parameters
203 ///
204 /// * `value` - The new reference to swap in.
205 ///
206 /// # Returns
207 ///
208 /// The old reference.
209 ///
210 /// # Example
211 ///
212 /// ```rust
213 /// use qubit_atomic::AtomicRef;
214 /// use std::sync::Arc;
215 ///
216 /// let atomic = AtomicRef::new(Arc::new(10));
217 /// let old = atomic.swap(Arc::new(20));
218 /// assert_eq!(*old, 10);
219 /// assert_eq!(*atomic.load(), 20);
220 /// ```
221 #[inline]
222 pub fn swap(&self, value: Arc<T>) -> Arc<T> {
223 self.inner.swap(value)
224 }
225
226 /// Compares and sets the reference atomically.
227 ///
228 /// If the current reference equals `current` (by pointer equality), sets
229 /// it to `new` and returns `Ok(())`. Otherwise, returns `Err(actual)`
230 /// where `actual` is the current reference.
231 ///
232 /// # Parameters
233 ///
234 /// * `current` - The expected current reference.
235 /// * `new` - The new reference to set if current matches.
236 ///
237 /// # Returns
238 ///
239 /// `Ok(())` if the pointer comparison succeeds and `new` is stored.
240 ///
241 /// # Errors
242 ///
243 /// Returns `Err(actual)` with the observed current reference when the
244 /// pointer comparison fails. On failure, `new` is not installed.
245 ///
246 /// # Note
247 ///
248 /// Comparison uses pointer equality (`Arc::ptr_eq`), not value equality.
249 ///
250 /// # Example
251 ///
252 /// ```rust
253 /// use qubit_atomic::AtomicRef;
254 /// use std::sync::Arc;
255 ///
256 /// let atomic = AtomicRef::new(Arc::new(10));
257 /// let current = atomic.load();
258 ///
259 /// assert!(atomic.compare_set(¤t, Arc::new(20)).is_ok());
260 /// assert_eq!(*atomic.load(), 20);
261 /// ```
262 #[inline]
263 pub fn compare_set(&self, current: &Arc<T>, new: Arc<T>) -> Result<(), Arc<T>> {
264 let prev = Guard::into_inner(self.inner.compare_and_swap(current, new));
265 if Arc::ptr_eq(&prev, current) {
266 Ok(())
267 } else {
268 Err(prev)
269 }
270 }
271
272 /// Compares and exchanges the reference atomically, returning the
273 /// previous reference.
274 ///
275 /// If the current reference equals `current` (by pointer equality), sets
276 /// it to `new` and returns the old reference. Otherwise, returns the
277 /// actual current reference.
278 ///
279 /// # Parameters
280 ///
281 /// * `current` - The expected current reference.
282 /// * `new` - The new reference to set if current matches.
283 ///
284 /// # Returns
285 ///
286 /// The reference observed before the operation completed. If it is pointer
287 /// equal to `current`, the exchange succeeded and `new` was stored.
288 /// Otherwise, it is the actual current reference that prevented the
289 /// exchange.
290 ///
291 /// # Note
292 ///
293 /// Comparison uses pointer equality (`Arc::ptr_eq`), not value equality.
294 ///
295 /// # Example
296 ///
297 /// ```rust
298 /// use qubit_atomic::AtomicRef;
299 /// use std::sync::Arc;
300 ///
301 /// let atomic = AtomicRef::new(Arc::new(10));
302 /// let current = atomic.load();
303 ///
304 /// let prev = atomic.compare_and_exchange(¤t, Arc::new(20));
305 /// assert!(Arc::ptr_eq(&prev, ¤t));
306 /// assert_eq!(*atomic.load(), 20);
307 /// ```
308 #[inline]
309 pub fn compare_and_exchange(&self, current: &Arc<T>, new: Arc<T>) -> Arc<T> {
310 Guard::into_inner(self.inner.compare_and_swap(current, new))
311 }
312
313 /// Updates the reference using a function, returning the old reference.
314 ///
315 /// Internally uses a CAS loop until the update succeeds.
316 ///
317 /// # Parameters
318 ///
319 /// * `f` - A function that takes the current reference and returns the
320 /// new reference.
321 ///
322 /// # Returns
323 ///
324 /// The old reference before the update.
325 ///
326 /// The closure may be called more than once when concurrent updates cause
327 /// CAS retries.
328 ///
329 /// # Example
330 ///
331 /// ```rust
332 /// use qubit_atomic::AtomicRef;
333 /// use std::sync::Arc;
334 ///
335 /// let atomic = AtomicRef::new(Arc::new(10));
336 /// let old = atomic.fetch_update(|x| Arc::new(**x * 2));
337 /// assert_eq!(*old, 10);
338 /// assert_eq!(*atomic.load(), 20);
339 /// ```
340 #[inline]
341 pub fn fetch_update<F>(&self, mut f: F) -> Arc<T>
342 where
343 F: FnMut(&Arc<T>) -> Arc<T>,
344 {
345 let mut current = self.load();
346 loop {
347 let new = f(¤t);
348 match self.compare_set(¤t, new) {
349 Ok(_) => return current,
350 Err(actual) => current = actual,
351 }
352 }
353 }
354
355 /// Updates the reference using a function, returning the new reference.
356 ///
357 /// Internally uses a CAS loop until the update succeeds.
358 ///
359 /// # Parameters
360 ///
361 /// * `f` - A function that takes the current reference and returns the
362 /// new reference.
363 ///
364 /// # Returns
365 ///
366 /// The reference committed by the successful update.
367 ///
368 /// The closure may be called more than once when concurrent updates cause
369 /// CAS retries.
370 ///
371 /// # Example
372 ///
373 /// ```rust
374 /// use qubit_atomic::AtomicRef;
375 /// use std::sync::Arc;
376 ///
377 /// let atomic = AtomicRef::new(Arc::new(10));
378 /// let new = atomic.update_and_get(|x| Arc::new(**x * 2));
379 /// assert_eq!(*new, 20);
380 /// assert_eq!(*atomic.load(), 20);
381 /// ```
382 #[inline]
383 pub fn update_and_get<F>(&self, mut f: F) -> Arc<T>
384 where
385 F: FnMut(&Arc<T>) -> Arc<T>,
386 {
387 let mut current = self.load();
388 loop {
389 let new = f(¤t);
390 let returned = Arc::clone(&new);
391 match self.compare_set(¤t, new) {
392 Ok(_) => return returned,
393 Err(actual) => current = actual,
394 }
395 }
396 }
397
398 /// Conditionally updates the reference using a function.
399 ///
400 /// Internally uses a pointer-based CAS loop until the update succeeds or
401 /// the closure rejects the current reference by returning `None`.
402 ///
403 /// # Parameters
404 ///
405 /// * `f` - A function that takes the current reference and returns the new
406 /// reference, or `None` to leave the current reference unchanged.
407 ///
408 /// # Returns
409 ///
410 /// `Some(old_reference)` when the update succeeds, or `None` when `f`
411 /// rejects the observed current reference.
412 ///
413 /// The closure may be called more than once when concurrent updates cause
414 /// CAS retries.
415 ///
416 /// # Example
417 ///
418 /// ```rust
419 /// use qubit_atomic::AtomicRef;
420 /// use std::sync::Arc;
421 ///
422 /// let atomic = AtomicRef::new(Arc::new(3));
423 /// let old = atomic.try_update(|current| {
424 /// (**current % 2 == 1).then_some(Arc::new(**current + 1))
425 /// });
426 /// assert_eq!(*old.unwrap(), 3);
427 /// assert_eq!(*atomic.load(), 4);
428 /// assert!(atomic
429 /// .try_update(|current| {
430 /// (**current % 2 == 1).then_some(Arc::new(**current + 1))
431 /// })
432 /// .is_none());
433 /// assert_eq!(*atomic.load(), 4);
434 /// ```
435 #[inline]
436 pub fn try_update<F>(&self, mut f: F) -> Option<Arc<T>>
437 where
438 F: FnMut(&Arc<T>) -> Option<Arc<T>>,
439 {
440 let mut current = self.load();
441 loop {
442 let new = f(¤t)?;
443 match self.compare_set(¤t, new) {
444 Ok(_) => return Some(current),
445 Err(actual) => current = actual,
446 }
447 }
448 }
449
450 /// Conditionally updates the reference using a function, returning the new
451 /// reference.
452 ///
453 /// Internally uses a pointer-based CAS loop until the update succeeds or
454 /// the closure rejects the current reference by returning `None`.
455 ///
456 /// # Parameters
457 ///
458 /// * `f` - A function that takes the current reference and returns the new
459 /// reference, or `None` to leave the current reference unchanged.
460 ///
461 /// # Returns
462 ///
463 /// `Some(new_reference)` when the update succeeds, or `None` when `f`
464 /// rejects the observed current reference.
465 ///
466 /// The closure may be called more than once when concurrent updates cause
467 /// CAS retries.
468 ///
469 /// # Example
470 ///
471 /// ```rust
472 /// use qubit_atomic::AtomicRef;
473 /// use std::sync::Arc;
474 ///
475 /// let atomic = AtomicRef::new(Arc::new(3));
476 /// let new = atomic.try_update_and_get(|current| {
477 /// (**current % 2 == 1).then_some(Arc::new(**current + 1))
478 /// });
479 /// assert_eq!(*new.unwrap(), 4);
480 /// assert_eq!(*atomic.load(), 4);
481 /// assert!(atomic
482 /// .try_update_and_get(|current| {
483 /// (**current % 2 == 1).then_some(Arc::new(**current + 1))
484 /// })
485 /// .is_none());
486 /// assert_eq!(*atomic.load(), 4);
487 /// ```
488 #[inline]
489 pub fn try_update_and_get<F>(&self, mut f: F) -> Option<Arc<T>>
490 where
491 F: FnMut(&Arc<T>) -> Option<Arc<T>>,
492 {
493 let mut current = self.load();
494 loop {
495 let new = f(¤t)?;
496 let returned = Arc::clone(&new);
497 match self.compare_set(¤t, new) {
498 Ok(_) => return Some(returned),
499 Err(actual) => current = actual,
500 }
501 }
502 }
503
504 /// Gets a reference to the underlying `ArcSwap`.
505 ///
506 /// This allows advanced users to access lower-level `ArcSwap` APIs for
507 /// custom synchronization strategies.
508 ///
509 /// # Returns
510 ///
511 /// A reference to the underlying `arc_swap::ArcSwap<T>`.
512 #[inline]
513 pub fn inner(&self) -> &ArcSwap<T> {
514 &self.inner
515 }
516}
517
518impl<T> Clone for AtomicRef<T> {
519 /// Clones the atomic reference.
520 ///
521 /// Creates a new `AtomicRef` that initially points to the same value as
522 /// the original, but subsequent atomic operations are independent.
523 ///
524 /// # Returns
525 ///
526 /// A new atomic reference initialized with a clone of the currently loaded
527 /// `Arc`.
528 #[inline]
529 fn clone(&self) -> Self {
530 Self::new(self.load())
531 }
532}
533
534impl<T: fmt::Debug> fmt::Debug for AtomicRef<T> {
535 /// Formats the currently loaded reference for debugging.
536 ///
537 /// # Parameters
538 ///
539 /// * `f` - The formatter receiving the debug representation.
540 ///
541 /// # Returns
542 ///
543 /// A formatting result from the formatter.
544 #[inline]
545 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546 f.debug_struct("AtomicRef")
547 .field("value", &self.load())
548 .finish()
549 }
550}
551
552impl<T: fmt::Display> fmt::Display for AtomicRef<T> {
553 /// Formats the currently loaded reference with display formatting.
554 ///
555 /// # Parameters
556 ///
557 /// * `f` - The formatter receiving the displayed value.
558 ///
559 /// # Returns
560 ///
561 /// A formatting result from the formatter.
562 #[inline]
563 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
564 write!(f, "{}", self.load())
565 }
566}