Struct atomig::Atomic

source ·
pub struct Atomic<T: Atom>(/* private fields */);
Expand description

The main type of this library: a generic atomic type.

Via the methods of this type you can perform various atomic operations. You can use any type T that implements Atom. This includes primitive atomics (the ones found in std::sync::atomic), other primitive types and potentially your own types. Additional methods are usable if T implements AtomLogic or AtomInteger.

All methods use Atom::pack and Atom::unpack to convert between the underlying atomic value and the real value T. For types that implement PrimitiveAtom, these two methods are a simple ID function, meaning that there is no runtime overhead. Other types should make sure their pack and unpack operations are fast, as they are used a lot in this type.

For all methods that do a comparison (e.g. compare_exchange), keep in mind that the comparison is performed on the bits of the underlying type which can sometimes lead to unexpected behavior. For example, for floats, there are many bit patterns that represent NaN. So the atomic might indeed store a NaN representation at a moment, but compare_exchange called with current = NaN might not swap, because both NaN differ in the bit representation.

The interface of this type very closely matches the interface of the atomic types in std::sync::atomic. The documentation was copied (and slightly adjusted) from there.

Implementations§

source§

impl<T: Atom> Atomic<T>

source

pub fn new(v: T) -> Self

Creates a new atomic value.

§Examples
use atomig::Atomic;

let x = Atomic::new(7u32);
source

pub const fn from_impl(v: <<T as Atom>::Repr as PrimitiveAtom>::Impl) -> Self

Creates a new atomic value from the underlying Atomic* type from std.

Since Atom is a trait and const fns in traits are not supported yet, the only way for this to be a const fn is to take the underyling atomic impl type directly.

This allows static Atomics to be created.

§Examples
use atomig::Atomic;
use std::sync::atomic::AtomicU32;

static X: Atomic<u32> = Atomic::from_impl(AtomicU32::new(7));
source

pub fn into_inner(self) -> T

Consumes the atomic and returns the contained value.

This is safe because passing self by value guarantees that no other threads are concurrently accessing the atomic data.

source

pub fn load(&self, order: Ordering) -> T

Loads the value from the atomic.

load takes an Ordering argument which describes the memory ordering of this operation. Possible values are SeqCst, Acquire and Relaxed.

§Panics

Panics if order is Release or AcqRel.

§Examples
use atomig::{Atomic, Ordering};

let x = Atomic::new(5);
assert_eq!(x.load(Ordering::SeqCst), 5);
source

pub fn store(&self, v: T, order: Ordering)

Stores a value into the atomic.

store takes an Ordering argument which describes the memory ordering of this operation. Possible values are SeqCst, Release and Relaxed.

§Panics

Panics if order is Acquire or AcqRel.

§Examples
use atomig::{Atomic, Ordering};

let x = Atomic::new(5);

x.store(10, Ordering::SeqCst);
assert_eq!(x.load(Ordering::SeqCst), 10);
source

pub fn swap(&self, v: T, order: Ordering) -> T

Stores a value into the atomic, returning the previous value.

swap takes an Ordering argument which describes the memory ordering of this operation. All ordering modes are possible. Note that using Acquire makes the store part of this operation Relaxed, and using Release makes the load part Relaxed.

§Examples
use atomig::{Atomic, Ordering};

let x = Atomic::new(5);
assert_eq!(x.swap(10, Ordering::SeqCst), 5);
source

pub fn compare_exchange( &self, current: T, new: T, success: Ordering, failure: Ordering ) -> Result<T, T>

Stores a value into the atomic if the current value is the same as the current value.

The return value is a result indicating whether the new value was written and containing the previous value. On success this value is guaranteed to be equal to current.

compare_exchange takes two Ordering arguments to describe the memory ordering of this operation. The first describes the required ordering if the operation succeeds while the second describes the required ordering when the operation fails. Using Acquire as success ordering makes the store part of this operation Relaxed, and using Release makes the successful load Relaxed. The failure ordering can only be SeqCst, Acquire or Relaxed and must be equivalent to or weaker than the success ordering.

§Examples
use atomig::{Atomic, Ordering};

let x = Atomic::new(5);

assert_eq!(
    x.compare_exchange(5, 10, Ordering::Acquire, Ordering::Relaxed),
    Ok(5),
);
assert_eq!(x.load(Ordering::Relaxed), 10);

assert_eq!(
    x.compare_exchange(6, 12, Ordering::SeqCst, Ordering::Acquire),
    Err(10),
);
assert_eq!(x.load(Ordering::Relaxed), 10);
source

pub fn compare_exchange_weak( &self, current: T, new: T, success: Ordering, failure: Ordering ) -> Result<T, T>

Stores a value into the atomic if the current value is the same as the current value.

Unlike compare_exchange, this function is allowed to spuriously fail even when the comparison succeeds, which can result in more efficient code on some platforms. The return value is a result indicating whether the new value was written and containing the previous value.

compare_exchange_weak takes two Ordering arguments to describe the memory ordering of this operation. The first describes the required ordering if the operation succeeds while the second describes the required ordering when the operation fails. Using Acquire as success ordering makes the store part of this operation Relaxed, and using Release makes the successful load Relaxed. The failure ordering can only be SeqCst, Acquire or Relaxed and must be equivalent to or weaker than the success ordering.

§Examples
use atomig::{Atomic, Ordering};

let x = Atomic::new(4);

let mut old = x.load(Ordering::Relaxed);
loop {
    let new = old * 2;
    match x.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
        Ok(_) => break,
        Err(x) => old = x,
    }
}
source

pub fn fetch_update<F>( &self, set_order: Ordering, fetch_order: Ordering, f: F ) -> Result<T, T>
where F: FnMut(T) -> Option<T>,

Fetches the value, and applies a function to it that returns an optional new value. Returns a Result of Ok(previous_value) if the function returned Some(_), else Err(previous_value).

Note: This may call the function multiple times if the value has been changed from other threads in the meantime, as long as the function returns Some(_), but the function will have been applied but once to the stored value.

fetch_update takes two Ordering arguments to describe the memory ordering of this operation. The first describes the required ordering for loads and failed updates while the second describes the required ordering when the operation finally succeeds. Beware that this is different from the two modes in compare_exchange!

Using Acquire as success ordering makes the store part of this operation Relaxed, and using Release makes the final successful load Relaxed. The (failed) load ordering can only be SeqCst, Acquire or Relaxed and must be equivalent to or weaker than the success ordering.

§Examples
use atomig::{Atomic, Ordering};

let x = Atomic::new(7);
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |_| None), Err(7));
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(7));
assert_eq!(x.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |x| Some(x + 1)), Ok(8));
assert_eq!(x.load(Ordering::SeqCst), 9);
source§

impl<T: AtomLogic> Atomic<T>

source

pub fn fetch_and(&self, val: T, order: Ordering) -> T

Bitwise “and” with the current value.

Performs a bitwise “and” operation on the current value and the argument val, and sets the new value to the result.

Returns the previous value.

fetch_and takes an Ordering argument which describes the memory ordering of this operation. All ordering modes are possible. Note that using Acquire makes the store part of this operation Relaxed, and using Release makes the load part Relaxed.

Examples

use atomig::{Atomic, Ordering};

let x = Atomic::new(0b101101);
assert_eq!(x.fetch_and(0b110011, Ordering::SeqCst), 0b101101);
assert_eq!(x.load(Ordering::SeqCst), 0b100001);
source

pub fn fetch_nand(&self, val: T, order: Ordering) -> T

Bitwise “nand” with the current value.

Performs a bitwise “nand” operation on the current value and the argument val, and sets the new value to the result.

Returns the previous value.

fetch_nand takes an Ordering argument which describes the memory ordering of this operation. All ordering modes are possible. Note that using Acquire makes the store part of this operation Relaxed, and using Release makes the load part Relaxed.

Examples

use atomig::{Atomic, Ordering};

let x = Atomic::new(0x13);
assert_eq!(x.fetch_nand(0x31, Ordering::SeqCst), 0x13);
assert_eq!(x.load(Ordering::SeqCst), !(0x13 & 0x31));
source

pub fn fetch_or(&self, val: T, order: Ordering) -> T

Bitwise “or” with the current value.

Performs a bitwise “or” operation on the current value and the argument val, and sets the new value to the result.

Returns the previous value.

fetch_or takes an Ordering argument which describes the memory ordering of this operation. All ordering modes are possible. Note that using Acquire makes the store part of this operation Relaxed, and using Release makes the load part Relaxed.

Examples

use atomig::{Atomic, Ordering};

let x = Atomic::new(0b101101);
assert_eq!(x.fetch_or(0b110011, Ordering::SeqCst), 0b101101);
assert_eq!(x.load(Ordering::SeqCst), 0b111111);
source

pub fn fetch_xor(&self, val: T, order: Ordering) -> T

Bitwise “xor” with the current value.

Performs a bitwise “xor” operation on the current value and the argument val, and sets the new value to the result.

Returns the previous value.

fetch_xor takes an Ordering argument which describes the memory ordering of this operation. All ordering modes are possible. Note that using Acquire makes the store part of this operation Relaxed, and using Release makes the load part Relaxed.

Examples

use atomig::{Atomic, Ordering};

let x = Atomic::new(0b101101);
assert_eq!(x.fetch_xor(0b110011, Ordering::SeqCst), 0b101101);
assert_eq!(x.load(Ordering::SeqCst), 0b011110);
source§

impl<T: AtomInteger> Atomic<T>

source

pub fn fetch_add(&self, val: T, order: Ordering) -> T

Adds to the current value, returning the previous value.

This operation wraps around on overflow.

fetch_add takes an Ordering argument which describes the memory ordering of this operation. All ordering modes are possible. Note that using Acquire makes the store part of this operation Relaxed, and using Release makes the load part Relaxed.

§Examples
use atomig::{Atomic, Ordering};

let x = Atomic::new(0);
assert_eq!(x.fetch_add(10, Ordering::SeqCst), 0);
assert_eq!(x.load(Ordering::SeqCst), 10);
source

pub fn fetch_sub(&self, val: T, order: Ordering) -> T

Subtracts from the current value, returning the previous value.

This operation wraps around on overflow.

fetch_sub takes an Ordering argument which describes the memory ordering of this operation. All ordering modes are possible. Note that using Acquire makes the store part of this operation Relaxed, and using Release makes the load part Relaxed.

§Examples
use atomig::{Atomic, Ordering};

let x = Atomic::new(20);
assert_eq!(x.fetch_sub(10, Ordering::SeqCst), 20);
assert_eq!(x.load(Ordering::SeqCst), 10);
source

pub fn fetch_max(&self, val: T, order: Ordering) -> T

Maximum with the current value.

Finds the maximum of the current value and the argument val, and sets the new value to the result.

Returns the previous value.

fetch_max takes an Ordering argument which describes the memory ordering of this operation. All ordering modes are possible. Note that using Acquire makes the store part of this operation Relaxed, and using Release makes the load part Relaxed.

§Examples
use atomig::{Atomic, Ordering};

let foo = Atomic::new(23);
assert_eq!(foo.fetch_max(42, Ordering::SeqCst), 23);
assert_eq!(foo.load(Ordering::SeqCst), 42);

If you want to obtain the maximum value in one step, you can use the following:

use atomig::{Atomic, Ordering};

let foo = Atomic::new(23);
let bar = 42;
let max_foo = foo.fetch_max(bar, Ordering::SeqCst).max(bar);
assert!(max_foo == 42);
source

pub fn fetch_min(&self, val: T, order: Ordering) -> T

Minimum with the current value.

Finds the minimum of the current value and the argument val, and sets the new value to the result.

Returns the previous value.

fetch_min takes an Ordering argument which describes the memory ordering of this operation. All ordering modes are possible. Note that using Acquire makes the store part of this operation Relaxed, and using Release makes the load part Relaxed.

§Examples
use atomig::{Atomic, Ordering};

let foo = Atomic::new(23);
assert_eq!(foo.fetch_min(42, Ordering::Relaxed), 23);
assert_eq!(foo.load(Ordering::Relaxed), 23);
assert_eq!(foo.fetch_min(22, Ordering::Relaxed), 23);
assert_eq!(foo.load(Ordering::Relaxed), 22);

If you want to obtain the minimum value in one step, you can use the following:

use atomig::{Atomic, Ordering};

let foo = Atomic::new(23);
let bar = 12;
let min_foo = foo.fetch_min(bar, Ordering::SeqCst).min(bar);
assert!(min_foo == 12);

Trait Implementations§

source§

impl<T: Atom + Debug> Debug for Atomic<T>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T: Atom + Default> Default for Atomic<T>

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<'de, T: Atom + Deserialize<'de>> Deserialize<'de> for Atomic<T>

source§

fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
source§

impl<T: Atom> From<T> for Atomic<T>

source§

fn from(v: T) -> Self

Converts to this type from the input type.
source§

impl<T: Atom + Serialize> Serialize for Atomic<T>

source§

fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl<T> RefUnwindSafe for Atomic<T>
where <<T as Atom>::Repr as PrimitiveAtom>::Impl: RefUnwindSafe,

§

impl<T> Send for Atomic<T>
where <<T as Atom>::Repr as PrimitiveAtom>::Impl: Send,

§

impl<T> Sync for Atomic<T>
where <<T as Atom>::Repr as PrimitiveAtom>::Impl: Sync,

§

impl<T> Unpin for Atomic<T>
where <<T as Atom>::Repr as PrimitiveAtom>::Impl: Unpin,

§

impl<T> UnwindSafe for Atomic<T>
where <<T as Atom>::Repr as PrimitiveAtom>::Impl: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,