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