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