StateCell

Struct StateCell 

Source
pub struct StateCell<State: StateMarker> { /* private fields */ }
Expand description

Lock-free snapshot cell with versioning.

Internally uses ArcSwap for atomic snapshot replacement and an AtomicU64 sequence counter for change detection.

Readers can cheaply peek or check if the snapshot changed without blocking writers.

§Internal Mutation

States can implement internal mutability (via RwLock, Mutex, atomics) and use mutate_internal to modify data without replacing the entire snapshot. The sequence counter still increments, notifying observers of changes.

§Example: Full Snapshot Replacement

#[derive(Default)]
struct Config {
    timeout: u64,
}
impl StateMarker for Config {}

let cell = StateCell::new(Config { timeout: 100 });
cell.publish(Config { timeout: 200 }); // Replace entire state

§Example: Internal Mutation

use std::sync::{Arc, RwLock};

struct Metrics {
    counters: Arc<RwLock<HashMap<String, u64>>>,
}
impl StateMarker for Metrics {}

let cell = StateCell::new(Metrics { ... });

// Modify without cloning the entire state
cell.mutate_internal(|state| {
    let mut counters = state.counters.write().unwrap();
    *counters.entry("requests".into()).or_insert(0) += 1;
});

// Observers detect the change via seq
if cell.changed_since(last_seq) {
    println!("Metrics updated!");
}

Implementations§

Source§

impl<S: StateMarker> StateCell<S>

Source

pub fn new(init: S) -> Self

Create a new cell with an initial state.

Source

pub fn new_arc(init: S) -> Arc<Self>

Create a new cell wrapped in Arc.

Source

pub fn new_default() -> Arc<Self>

Create a new cell with the state’s default value, wrapped in Arc.

Source

pub fn publish_arc(&self, next: Arc<S>)

Publish a new snapshot (by Arc).

Source

pub fn publish(&self, next: S)

Publish a new snapshot (by value).

Source

pub fn update(&self, next: Arc<S>)

Alias for publishing; can be used by producers.

Source

pub fn peek(&self) -> Guard<Arc<S>>

Provides a temporary borrow of the object inside.

This returns a proxy object allowing access to the thing held inside. However, there’s only limited amount of possible cheap proxies in existence for each thread ‒ if more are created, it falls back to equivalent of load internally.

This is therefore a good choice to use for eg. searching a data structure or juggling the pointers around a bit, but not as something to store in larger amounts. The rule of thumb is this is suited for local variables on stack, but not in long-living data structures.

§Consistency

In case multiple related operations are to be done on the loaded value, it is generally recommended to call peek just once and keep the result over calling it multiple times. First, keeping it is usually faster. But more importantly, the value can change between the calls to peek, returning different objects, which could lead to logical inconsistency. Keeping the result makes sure the same object is used.

Source

pub fn peek_if_changed(&self, last_seq: &mut u64) -> Option<Guard<Arc<S>>>

Load a snapshot only if sequence changed since last_seq. Updates last_seq if changed.

Source

pub fn load(&self) -> Arc<S>

Get the current snapshot as an owned Arc.

Source

pub fn with<R>(&self, f: impl FnOnce(&S, u64) -> R) -> R

Apply a closure to the current snapshot and sequence.

Source

pub fn with_if_changed<R>( &self, last_seq: &mut u64, f: impl FnOnce(&S) -> R, ) -> Option<R>

Apply a closure if the sequence changed since last_seq. Updates last_seq if changed.

Source

pub fn seq(&self) -> u64

Current sequence number.

Source

pub fn changed_since(&self, last: u64) -> bool

Check if sequence changed since last.

Source

pub fn mutate_internal<F>(&self, f: F)
where F: FnOnce(&S),

Modify internal state without replacing the snapshot.

This method allows calling a closure that can mutate the state’s internal data (e.g., via RwLock, Mutex, or atomics) without creating a new Arc snapshot. The sequence counter is incremented to notify observers of the change.

§Example
// State with internal mutability
struct MyState {
    data: Arc<RwLock<Vec<String>>>,
}

let cell = StateCell::new(MyState { ... });

// Modify without replacing snapshot
cell.mutate_internal(|state| {
    let mut data = state.data.write().unwrap();
    data.push("new item".to_string());
});
Source

pub fn mutate_internal_with<F, R>(&self, f: F) -> R
where F: FnOnce(&S) -> R,

Modify internal state and return a result.

Similar to mutate_internal, but allows the closure to return a value.

§Example
let count = cell.mutate_internal_with(|state| {
    let mut data = state.data.write().unwrap();
    data.push("item".to_string());
    data.len()
});

Trait Implementations§

Source§

impl<State: Debug + StateMarker> Debug for StateCell<State>

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<State> !Freeze for StateCell<State>

§

impl<State> RefUnwindSafe for StateCell<State>
where State: RefUnwindSafe,

§

impl<State> Send for StateCell<State>

§

impl<State> Sync for StateCell<State>

§

impl<State> Unpin for StateCell<State>

§

impl<State> UnwindSafe for StateCell<State>
where State: RefUnwindSafe,

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

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,