pub struct AtomicU64 { /* private fields */ }Expand description
Atomic 64-bit unsigned integer.
Provides easy-to-use atomic operations with automatic memory ordering selection. All methods are thread-safe and can be shared across threads.
§Memory Ordering Strategy
This type uses carefully chosen default memory orderings:
- Read operations (
load): UseAcquireordering to ensure visibility of writes from other threads. - Write operations (
store): UseReleaseordering to ensure writes are visible to other threads. - Read-Modify-Write (
swap, CAS): UseAcqRelordering for both read and write synchronization. - Counter arithmetic (
fetch_inc,fetch_dec,fetch_add,fetch_sub): UseRelaxedordering for optimal performance in pure counting scenarios where no other data needs synchronization. Use the corresponding_with_orderingvariants when the counter value is used as a synchronization signal. These operations intentionally follow Rust integer atomic wrapping semantics on overflow and underflow. - CAS-based arithmetic and updates (
fetch_mul,fetch_div,fetch_update,update_and_get,try_update,try_update_and_get,fetch_accumulate,accumulate_and_get): UseAcqRelordering on successful update andAcquireordering on failed CAS attempts. - Bit operations (
fetch_and,fetch_or, etc.): UseAcqRelordering as they typically synchronize flag states. - Max/Min operations: Use
AcqRelordering as they often coordinate with threshold-based logic.
For advanced use cases requiring different memory orderings,
use inner() to access the underlying backend atomic type.
§Features
- Automatic memory ordering selection
- Rich set of integer operations (increment, decrement, arithmetic, etc.)
- Zero-cost abstraction with inline methods
- Access to underlying type via
inner()for advanced use cases
§Example
use qubit_atomic::Atomic;
use std::sync::Arc;
use std::thread;
let counter = Arc::new(Atomic::<u64>::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = counter.clone();
let handle = thread::spawn(move || {
for _ in 0..10 {
counter.fetch_inc();
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(counter.load(), 100);Implementations§
Source§impl AtomicU64
impl AtomicU64
Sourcepub fn load(&self) -> u64
pub fn load(&self) -> u64
Loads the current value.
§Memory Ordering
Uses Acquire ordering to ensure that:
- This load operation happens-before any subsequent memory operations in the current thread.
- If another thread performed a
Releasestore, all writes before that store are visible after this load.
This is the standard choice for reading shared state that may have been modified by other threads.
§Returns
The current value.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(42);
assert_eq!(atomic.load(), 42);Sourcepub fn store(&self, value: u64)
pub fn store(&self, value: u64)
Stores a new value.
§Memory Ordering
Uses Release ordering to ensure that:
- All memory operations before this store in the current thread happen-before the store.
- When another thread performs an
Acquireload and sees this value, all writes before this store become visible.
This is the standard choice for publishing data to other threads.
§Parameters
value- The new value to store.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(0);
atomic.store(42);
assert_eq!(atomic.load(), 42);Sourcepub fn swap(&self, value: u64) -> u64
pub fn swap(&self, value: u64) -> u64
Swaps the current value with a new value, returning the old value.
§Memory Ordering
Uses AcqRel ordering to ensure that:
- Acquire: Reads the current value and establishes
happens-before with prior
Releaseoperations. - Release: Writes the new value and makes all prior
writes visible to subsequent
Acquireoperations.
This is the standard choice for atomic exchange operations that both read and write.
§Parameters
value- The new value to swap in.
§Returns
The old value.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let old = atomic.swap(20);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 20);Sourcepub fn compare_set(&self, current: u64, new: u64) -> Result<(), u64>
pub fn compare_set(&self, current: u64, new: u64) -> Result<(), u64>
Compares and sets the value atomically.
If the current value equals current, sets it to new and
returns Ok(()). Otherwise, returns Err(actual) where
actual is the current value.
§Memory Ordering
- Success: Uses
AcqRelordering (both Acquire and Release) to synchronize with other threads. - Failure: Uses
Acquireordering to see the latest value written by other threads.
This is the standard CAS pattern: on success, we need Release to publish our write; on failure, we need Acquire to see what value actually exists.
§Parameters
current- The expected current value.new- The new value to set if current matches.
§Returns
Ok(()) when the value was replaced.
§Errors
Returns Err(actual) with the observed value when the
comparison fails. In that case, new is not stored.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
assert!(atomic.compare_set(10, 20).is_ok());
assert_eq!(atomic.load(), 20);Sourcepub fn compare_set_weak(&self, current: u64, new: u64) -> Result<(), u64>
pub fn compare_set_weak(&self, current: u64, new: u64) -> Result<(), u64>
Weak version of compare-and-set.
May spuriously fail even when the comparison succeeds. Should be used in a loop.
Uses AcqRel ordering on success and Acquire ordering on
failure.
§Parameters
current- The expected current value.new- The new value to set if current matches.
§Returns
Ok(()) when the value was replaced.
§Errors
Returns Err(actual) with the observed value when the
comparison fails, including possible spurious failures. In
that case, new is not stored.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let mut current = atomic.load();
loop {
match atomic.compare_set_weak(current, current + 1) {
Ok(_) => break,
Err(actual) => current = actual,
}
}
assert_eq!(atomic.load(), 11);Sourcepub fn compare_and_exchange(&self, current: u64, new: u64) -> u64
pub fn compare_and_exchange(&self, current: u64, new: u64) -> u64
Compares and exchanges the value atomically, returning the previous value.
If the current value equals current, sets it to new and
returns the old value. Otherwise, returns the actual current
value.
Uses AcqRel ordering on success and Acquire ordering on
failure.
§Parameters
current- The expected current value.new- The new value to set if current matches.
§Returns
The value observed before the operation completed. If the
returned value equals current, the exchange succeeded;
otherwise it is the actual value that prevented the exchange.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let prev = atomic.compare_and_exchange(10, 20);
assert_eq!(prev, 10);
assert_eq!(atomic.load(), 20);Sourcepub fn compare_and_exchange_weak(
&self,
current: u64,
new: u64,
) -> Result<u64, u64>
pub fn compare_and_exchange_weak( &self, current: u64, new: u64, ) -> Result<u64, u64>
Weak version of compare-and-exchange.
May spuriously fail even when the comparison succeeds. Should be used in a loop.
Uses AcqRel ordering on success and Acquire ordering on
failure.
§Parameters
current- The expected current value.new- The new value to set if current matches.
§Returns
Ok(previous) when the value was replaced, or Err(actual)
when the comparison failed, including possible spurious
failure.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let mut current = atomic.load();
loop {
match atomic.compare_and_exchange_weak(current, current + 5) {
Ok(previous) => {
assert_eq!(previous, current);
break;
}
Err(actual) => current = actual,
}
}
assert_eq!(atomic.load(), 15);Sourcepub fn fetch_inc(&self) -> u64
pub fn fetch_inc(&self) -> u64
Increments the value by 1, returning the old value.
Arithmetic wraps on overflow, matching Rust atomic integer operations.
§Memory Ordering
Uses Relaxed ordering for optimal performance. This is
appropriate for pure counters where:
- Only the counter value itself needs to be atomic.
- No other data needs to be synchronized.
- The typical use case is statistics/counting.
Rationale: Counters are the most common use of atomic
integers. Using Relaxed provides maximum performance
(especially on ARM) while maintaining correctness for the
counter value itself. If you need to synchronize other
data, use load()/store() with their stronger orderings.
§Returns
The old value before incrementing.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_inc();
assert_eq!(old, 10);
assert_eq!(atomic.load(), 11);Sourcepub fn fetch_inc_with_ordering(&self, ordering: Ordering) -> u64
pub fn fetch_inc_with_ordering(&self, ordering: Ordering) -> u64
Increments the value by 1 with an explicit memory ordering, returning the old value.
Arithmetic wraps on overflow, matching Rust atomic integer operations.
§Parameters
ordering- The memory ordering used by the atomic read-modify-write operation.
§Returns
The old value before incrementing.
§Example
use qubit_atomic::Atomic;
use std::sync::atomic::Ordering;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_inc_with_ordering(Ordering::AcqRel);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 11);Sourcepub fn fetch_dec(&self) -> u64
pub fn fetch_dec(&self) -> u64
Decrements the value by 1, returning the old value.
Arithmetic wraps on underflow, matching Rust atomic integer operations.
Uses Relaxed ordering.
§Returns
The old value before decrementing.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_dec();
assert_eq!(old, 10);
assert_eq!(atomic.load(), 9);Sourcepub fn fetch_dec_with_ordering(&self, ordering: Ordering) -> u64
pub fn fetch_dec_with_ordering(&self, ordering: Ordering) -> u64
Decrements the value by 1 with an explicit memory ordering, returning the old value.
Arithmetic wraps on underflow, matching Rust atomic integer operations.
§Parameters
ordering- The memory ordering used by the atomic read-modify-write operation.
§Returns
The old value before decrementing.
§Example
use qubit_atomic::Atomic;
use std::sync::atomic::Ordering;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_dec_with_ordering(Ordering::AcqRel);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 9);Sourcepub fn fetch_add(&self, delta: u64) -> u64
pub fn fetch_add(&self, delta: u64) -> u64
Adds a delta to the value, returning the old value.
Arithmetic wraps on overflow and underflow, matching Rust atomic integer operations.
§Memory Ordering
Uses Relaxed ordering for the same reasons as
fetch_inc(): optimal performance for pure counting
scenarios. See fetch_inc() documentation for detailed
rationale.
§Parameters
delta- The value to add.
§Returns
The old value before adding.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_add(5);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 15);Sourcepub fn fetch_add_with_ordering(&self, delta: u64, ordering: Ordering) -> u64
pub fn fetch_add_with_ordering(&self, delta: u64, ordering: Ordering) -> u64
Adds a delta to the value with an explicit memory ordering, returning the old value.
Arithmetic wraps on overflow and underflow, matching Rust atomic integer operations.
§Parameters
delta- The value to add.ordering- The memory ordering used by the atomic read-modify-write operation.
§Returns
The old value before adding.
§Example
use qubit_atomic::Atomic;
use std::sync::atomic::Ordering;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_add_with_ordering(5, Ordering::AcqRel);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 15);Sourcepub fn fetch_sub(&self, delta: u64) -> u64
pub fn fetch_sub(&self, delta: u64) -> u64
Subtracts a delta from the value, returning the old value.
Arithmetic wraps on overflow and underflow, matching Rust atomic integer operations.
Uses Relaxed ordering.
§Parameters
delta- The value to subtract.
§Returns
The old value before subtracting.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_sub(3);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 7);Sourcepub fn fetch_sub_with_ordering(&self, delta: u64, ordering: Ordering) -> u64
pub fn fetch_sub_with_ordering(&self, delta: u64, ordering: Ordering) -> u64
Subtracts a delta from the value with an explicit memory ordering, returning the old value.
Arithmetic wraps on overflow and underflow, matching Rust atomic integer operations.
§Parameters
delta- The value to subtract.ordering- The memory ordering used by the atomic read-modify-write operation.
§Returns
The old value before subtracting.
§Example
use qubit_atomic::Atomic;
use std::sync::atomic::Ordering;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_sub_with_ordering(3, Ordering::AcqRel);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 7);Sourcepub fn fetch_mul(&self, factor: u64) -> u64
pub fn fetch_mul(&self, factor: u64) -> u64
Multiplies the value by a factor, returning the old value.
Arithmetic wraps on overflow and underflow.
§Memory Ordering
Internally uses a CAS loop via compare_set, which uses
AcqRel ordering on success and Acquire ordering on
failure.
§Parameters
factor- The factor to multiply by.
§Returns
The old value before multiplication.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_mul(3);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 30);Sourcepub fn fetch_div(&self, divisor: u64) -> u64
pub fn fetch_div(&self, divisor: u64) -> u64
Divides the value by a divisor, returning the old value.
Arithmetic uses wrapping division. For signed integers,
MIN / -1 wraps to MIN.
§Memory Ordering
Internally uses a CAS loop via compare_set, which uses
AcqRel ordering on success and Acquire ordering on
failure.
§Parameters
divisor- The divisor to divide by.
§Returns
The old value before division.
§Panics
Panics if divisor is zero.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(30);
let old = atomic.fetch_div(3);
assert_eq!(old, 30);
assert_eq!(atomic.load(), 10);Sourcepub fn fetch_and(&self, value: u64) -> u64
pub fn fetch_and(&self, value: u64) -> u64
Performs bitwise AND, returning the old value.
§Memory Ordering
Uses AcqRel ordering because bit operations typically
manipulate flag bits that coordinate access to other data.
Rationale: Unlike pure counters, bit operations are commonly used for:
- State flags (INITIALIZED, RUNNING, STOPPED, etc.)
- Feature toggles
- Permission masks
These scenarios require synchronization with related data,
so we use the stronger AcqRel ordering by default.
§Parameters
value- The value to AND with.
§Returns
The old value before the operation.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(0b1111);
let old = atomic.fetch_and(0b1100);
assert_eq!(old, 0b1111);
assert_eq!(atomic.load(), 0b1100);Sourcepub fn fetch_or(&self, value: u64) -> u64
pub fn fetch_or(&self, value: u64) -> u64
Performs bitwise OR, returning the old value.
Uses AcqRel ordering.
§Parameters
value- The value to OR with.
§Returns
The old value before the operation.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(0b1100);
let old = atomic.fetch_or(0b0011);
assert_eq!(old, 0b1100);
assert_eq!(atomic.load(), 0b1111);Sourcepub fn fetch_xor(&self, value: u64) -> u64
pub fn fetch_xor(&self, value: u64) -> u64
Performs bitwise XOR, returning the old value.
Uses AcqRel ordering.
§Parameters
value- The value to XOR with.
§Returns
The old value before the operation.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(0b1100);
let old = atomic.fetch_xor(0b0110);
assert_eq!(old, 0b1100);
assert_eq!(atomic.load(), 0b1010);Sourcepub fn fetch_not(&self) -> u64
pub fn fetch_not(&self) -> u64
Performs bitwise NOT, returning the old value.
This is a convenience method equivalent to XOR with an all-ones
bit mask. Uses AcqRel ordering.
§Returns
The old value before the operation.
§Example
use qubit_atomic::Atomic;
let value: u64 = 42;
let atomic = Atomic::<u64>::new(value);
let old = atomic.fetch_not();
assert_eq!(old, value);
assert_eq!(atomic.load(), !value);§Note
This method is implemented using fetch_xor(!0) because
hardware and LLVM do not provide a native atomic NOT
instruction. The compiler will optimize this into
efficient machine code.
Sourcepub fn fetch_update<F>(&self, f: F) -> u64
pub fn fetch_update<F>(&self, f: F) -> u64
Updates the value using a function, returning the old value.
Internally uses a CAS loop until the update succeeds.
§Parameters
f- A function that takes the current value and returns the new value.
§Returns
The old value before the update.
The closure may be called more than once when concurrent updates cause CAS retries.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_update(|x| x * 2);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 20);Sourcepub fn update_and_get<F>(&self, f: F) -> u64
pub fn update_and_get<F>(&self, f: F) -> u64
Updates the value using a function, returning the new value.
Internally uses a CAS loop until the update succeeds.
§Parameters
f- A function that takes the current value and returns the new value.
§Returns
The value committed by the successful update.
The closure may be called more than once when concurrent updates cause CAS retries.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let new = atomic.update_and_get(|x| x * 2);
assert_eq!(new, 20);
assert_eq!(atomic.load(), 20);Sourcepub fn try_update<F>(&self, f: F) -> Option<u64>
pub fn try_update<F>(&self, f: F) -> Option<u64>
Conditionally updates the value using a function.
Internally uses a CAS loop until the update succeeds or the
closure rejects the current value by returning None.
§Parameters
f- A function that takes the current value and returns the new value, orNoneto leave the value unchanged.
§Returns
Some(old_value) when the update succeeds, or None when
f rejects the observed current value.
The closure may be called more than once when concurrent updates cause CAS retries.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(3);
assert_eq!(atomic.try_update(|x| (x % 2 == 1).then_some(x + 1)), Some(3));
assert_eq!(atomic.load(), 4);
assert_eq!(atomic.try_update(|x| (x % 2 == 1).then_some(x + 1)), None);
assert_eq!(atomic.load(), 4);Sourcepub fn try_update_and_get<F>(&self, f: F) -> Option<u64>
pub fn try_update_and_get<F>(&self, f: F) -> Option<u64>
Conditionally updates the value using a function, returning the new value.
Internally uses a CAS loop until the update succeeds or the
closure rejects the current value by returning None.
§Parameters
f- A function that takes the current value and returns the new value, orNoneto leave the value unchanged.
§Returns
Some(new_value) when the update succeeds, or None when
f rejects the observed current value.
The closure may be called more than once when concurrent updates cause CAS retries.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(3);
assert_eq!(
atomic.try_update_and_get(|x| (x % 2 == 1).then_some(x + 1)),
Some(4),
);
assert_eq!(atomic.load(), 4);
assert_eq!(
atomic.try_update_and_get(|x| (x % 2 == 1).then_some(x + 1)),
None,
);
assert_eq!(atomic.load(), 4);Sourcepub fn fetch_accumulate<F>(&self, x: u64, f: F) -> u64
pub fn fetch_accumulate<F>(&self, x: u64, f: F) -> u64
Accumulates a value using a binary function, returning the old value.
Internally uses a CAS loop until the update succeeds.
§Parameters
x- The value to accumulate with.f- A binary function that takes the current value andx, returning the new value.
§Returns
The old value before the accumulation.
The closure may be called more than once when concurrent updates cause CAS retries.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let old = atomic.fetch_accumulate(5, |a, b| a + b);
assert_eq!(old, 10);
assert_eq!(atomic.load(), 15);Sourcepub fn accumulate_and_get<F>(&self, x: u64, f: F) -> u64
pub fn accumulate_and_get<F>(&self, x: u64, f: F) -> u64
Accumulates a value using a binary function, returning the new value.
Internally uses a CAS loop until the update succeeds.
§Parameters
x- The value to accumulate with.f- A binary function that takes the current value andx, returning the new value.
§Returns
The value committed by the successful accumulation.
The closure may be called more than once when concurrent updates cause CAS retries.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
let new = atomic.accumulate_and_get(5, |a, b| a + b);
assert_eq!(new, 15);
assert_eq!(atomic.load(), 15);Sourcepub fn fetch_max(&self, value: u64) -> u64
pub fn fetch_max(&self, value: u64) -> u64
Sets the value to the maximum of the current value and the given value, returning the old value.
§Memory Ordering
Uses AcqRel ordering because max/min operations often
coordinate with threshold-based logic and related metadata.
Rationale: Common use cases include:
- Peak value tracking with timestamp recording
- High-water marks that trigger alerts
- Resource allocation thresholds
These scenarios typically need to synchronize with other
data (timestamps, alert states, etc.), so we use AcqRel
for safety.
§Parameters
value- The value to compare with.
§Returns
The old value before the operation.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
atomic.fetch_max(20);
assert_eq!(atomic.load(), 20);
atomic.fetch_max(15);
assert_eq!(atomic.load(), 20);Sourcepub fn fetch_min(&self, value: u64) -> u64
pub fn fetch_min(&self, value: u64) -> u64
Sets the value to the minimum of the current value and the given value, returning the old value.
Uses AcqRel ordering.
§Parameters
value- The value to compare with.
§Returns
The old value before the operation.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<u64>::new(10);
atomic.fetch_min(5);
assert_eq!(atomic.load(), 5);
atomic.fetch_min(8);
assert_eq!(atomic.load(), 5);Sourcepub fn inner(&self) -> &AtomicU64
pub fn inner(&self) -> &AtomicU64
Gets a reference to the underlying backend atomic type.
This allows direct access to the backend atomic operations for advanced use cases that require fine-grained control over memory ordering.
§Returns
A reference to the underlying backend atomic type std::sync::atomic::AtomicU64.
§Example
use qubit_atomic::Atomic;
use std::sync::atomic::Ordering;
let atomic = Atomic::<u64>::new(0);
atomic.inner().store(42, Ordering::Relaxed);
assert_eq!(atomic.inner().load(Ordering::Relaxed), 42);