Skip to main content

Atom

Struct Atom 

pub struct Atom<T>
where T: Send + Sync + 'static,
{ /* private fields */ }
Expand description

An atomically swapped value, from the kovan crate: see its docs. A single-value container with safe memory reclamation: loads, stores and swaps are wait-free, and rcu() is lock-free (it retries only after another thread’s write).

Provides cheap reads via load() and atomic writes via store(), swap(), and rcu(). Old values are automatically retired through kovan’s wait-free reclamation.

Unlike ArcSwap, Atom<T> works with any T: Send + Sync + 'static: there is no requirement to wrap values in Arc.

§Examples

use kovan::Atom;

// Create and read
let config = Atom::new(vec![1, 2, 3]);
assert_eq!(config.load().len(), 3);

// Atomic update: readers see old or new, never torn
config.store(vec![4, 5, 6, 7]);
assert_eq!(config.load().len(), 4);

Implementations§

§

impl<T> Atom<T>
where T: Send + Sync + 'static,

pub fn new(val: T) -> Atom<T>

Creates a new Atom containing val.

The value is heap-allocated and managed by kovan’s reclamation system.

§Examples
use kovan::Atom;
let atom = Atom::new(42);

pub fn into_inner(self) -> T

Consumes the Atom and returns the inner value.

This is safe because consuming self guarantees no concurrent access.

§Examples
use kovan::Atom;
let atom = Atom::new(String::from("hello"));
let s = atom.into_inner();
assert_eq!(s, "hello");

pub fn load(&self) -> AtomGuard<'_, T>

Loads the current value, returning a guard that dereferences to &T.

This is the cheapest read operation: a pin, one atomic load and an epoch check against the pin’s cache. The returned [AtomGuard] keeps the value alive; it will not be reclaimed until the guard is dropped.

§Consistency

Call load() once and reuse the guard for multiple accesses to ensure you see a consistent snapshot. Calling load() multiple times may return different values if another thread updated the Atom in between.

§Examples
use kovan::Atom;

let atom = Atom::new(42);
let val = atom.load();
assert_eq!(*val, 42);

pub fn load_clone(&self) -> T
where T: Clone,

Loads and clones the current value.

Equivalent to atom.load().clone() but expressed as a single call. Use this when you need an owned copy and T: Clone.

§Examples
use kovan::Atom;

let atom = Atom::new(vec![1, 2, 3]);
let owned: Vec<i32> = atom.load_clone();

pub fn peek<R>(&self, f: impl FnOnce(&T) -> R) -> R

Calls a closure with a reference to the current value.

This is useful when you want to inspect the value without holding onto a guard. The closure runs within a kovan critical section.

§Examples
use kovan::Atom;

let atom = Atom::new(vec![1, 2, 3]);
let len = atom.peek(|v| v.len());
assert_eq!(len, 3);

pub fn store(&self, val: T)

Atomically replaces the current value.

The old value is retired for safe reclamation: it will be freed once no reader holds a guard referencing it.

§Examples
use kovan::Atom;

let atom = Atom::new(1);
atom.store(2);
assert_eq!(*atom.load(), 2);

pub fn swap(&self, val: T) -> Removed<T>

Atomically replaces the current value and returns the previous one wrapped in [Removed<T>].

The old value stays in its node, where readers that loaded it before the swap still read it, and the returned [Removed<T>] derefs to that same object. Unlike store(), the old node is not retired at once: dropping the Removed<T> retires it, and T’s destructor runs once no reader is left.

§Examples
use kovan::Atom;

let atom = Atom::new(String::from("hello"));
let old = atom.swap(String::from("world"));
assert_eq!(*old, "hello");
assert_eq!(*atom.load(), "world");

pub fn compare_and_swap<'a>( &'a self, current: &AtomGuard<'_, T>, new: T, ) -> Result<AtomGuard<'a, T>, T>

Compare-and-swap: atomically replace the value if it hasn’t changed.

Loads the current pointer, compares it to current’s pointer. If they match, stores new and retires the old value. Returns Ok(guard) with the new value on success, or Err(new) returning the rejected value.

§Examples
use kovan::Atom;

let atom = Atom::new(1);
let current = atom.load();
// This succeeds because nobody changed it
assert!(atom.compare_and_swap(&current, 2).is_ok());
assert_eq!(*atom.load(), 2);

pub fn rcu<F>(&self, f: F)
where F: FnMut(&T) -> T,

Read-Copy-Update: atomically apply a transformation.

Loads the current value, calls f(&T) to produce a new value, then attempts a CAS. If another thread modified the value between the load and CAS, the operation retries automatically.

The closure f may be called multiple times on contention. Keep it cheap: do expensive work before calling rcu.

§Examples
use kovan::Atom;

let counter = Atom::new(0u64);

// Thread-safe increment (retries on contention)
counter.rcu(|val| val + 1);
assert_eq!(*counter.load(), 1);

pub fn map<'a, R, F>(&'a self, f: F) -> AtomMap<'a, T, R, F>
where R: 'a, F: Fn(&T) -> &R,

Create a mapped view that projects into a field of T.

Returns an [AtomMap] that loads T and applies f to project into a sub-field. Useful for passing configuration sub-sections to components without exposing the full T.

Keep f cheap: it runs on every load.

§Examples
use kovan::Atom;

struct Config { db_port: u16, workers: usize }
let config = Atom::new(Config { db_port: 5432, workers: 4 });

let port_view = config.map(|c| &c.db_port);
assert_eq!(*port_view.load(), 5432);

Trait Implementations§

§

impl<T> Debug for Atom<T>
where T: Send + Sync + 'static + Debug,

§

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

Formats the value using the given formatter. Read more
§

impl<T> Default for Atom<T>
where T: Send + Sync + 'static + Default,

§

fn default() -> Atom<T>

Creates an Atom containing T::default().

§

impl<T> Drop for Atom<T>
where T: Send + Sync + 'static,

§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
§

impl<T> From<T> for Atom<T>
where T: Send + Sync + 'static,

§

fn from(val: T) -> Atom<T>

Converts to this type from the input type.
§

impl<T> Send for Atom<T>
where T: Send + Sync + 'static,

§

impl<T> Sync for Atom<T>
where T: Send + Sync + 'static,

Auto Trait Implementations§

§

impl<T> !Freeze for Atom<T>

§

impl<T> !RefUnwindSafe for Atom<T>

§

impl<T> !UnwindSafe for Atom<T>

§

impl<T> Unpin for Atom<T>

§

impl<T> UnsafeUnpin for Atom<T>

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<!> for T

Source§

fn from(t: !) -> T

Converts to this type from the input type.
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.

§

impl<T> MaybeSend for T
where T: Send + ?Sized,

Source§

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

Source§

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>,

Source§

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.