Skip to main content

SharedState

Struct SharedState 

Source
pub struct SharedState<P, S, T>
where S: SharedStorage,
{ /* private fields */ }
Expand description

Shared state using an explicit, replaceable storage backend.

SharedState is the runtime boundary for this library. Owned state tokens carry their current state only in the type system. Shared containers such as Rc<RefCell<_>>, Arc<Mutex<_>>, and Arc<RwLock<_>> need one authoritative runtime marker because aliases can request typed views at different times.

A borrow checks that runtime marker first. After the check succeeds, the returned value is again a statically typed State view, so ordinary read-only state-machine methods regain compile-time guarantees:

use magicstatemachines::{SArcMutex, transition};
use test_def::{Online, states::{Connected, Disconnected}};

let shared = SArcMutex::<Connection>::new::<Disconnected>(
    Connection::new("localhost:8080"),
);

{
    let disconnected = shared.borrow_mut::<Disconnected>()?;
    let connected = transition!(disconnected);
    drop(connected); // commits `Connected` back to the shared container.
}

let connected = shared.borrow::<Connected>()?;
let online = shared.borrow::<Online>()?;

The storage backend is an explicit type parameter. The built-in aliases cover the common cases:

Union markers can be borrowed, but cannot be stored as the committed runtime state:

use magicstatemachines::{SArcMutex, StateMachineDefinition, StateMachineImpl, States};

struct Machine;
struct Standin;

States! {
    A;
    B;
}

StateMachineDefinition! {
    for Standin;

    pub Initial: A;
    transition A => B();
    union Any: A | B;
}

StateMachineImpl! {
    Machine: Standin;

    transition A => B();
}

let _state = SArcMutex::<Machine>::new::<Any>(Machine);

Implementations§

Source§

impl<Storage, T> SharedState<Rc<Storage::Storage<T>>, Storage, T>
where Storage: SharedStorage,

Source

pub fn downgrade(&self) -> WeakSRc<Storage, T>

Creates a weak handle to this Rc-backed shared state.

The weak handle remembers the same SharedStorage backend as the strong handle. After upgrade, callers use the normal borrow and borrow_mut APIs, so state mismatches and backend borrow errors are still reported by those APIs:

let shared = SRcRefCell::<Connection>::new::<Disconnected>(connection);
let weak: WeakSRcRefCell<Connection> = shared.downgrade();

let shared = weak.upgrade().expect("at least one strong handle remains");
let disconnected = shared.borrow::<Disconnected>()?;
Source§

impl<Storage, T> SharedState<Arc<Storage::Storage<T>>, Storage, T>
where Storage: SharedStorage,

Source

pub fn downgrade(&self) -> WeakSArc<Storage, T>

Creates a weak handle to this Arc-backed shared state.

Upgrade failure means all strong Arc handles were dropped. It is not a state-machine error and it is independent from wrong-state or lock errors:

let shared = SArcMutex::<Connection>::new::<Disconnected>(connection);
let weak: WeakSArcMutex<Connection> = shared.downgrade();

if let Some(shared) = weak.upgrade() {
    let disconnected = shared.borrow::<Disconnected>()?;
}
Source§

impl<P, Backend, T> SharedState<P, Backend, T>
where Backend: SharedStorage, P: From<Backend::Storage<T>> + AsRef<Backend::Storage<T>>, T: StateMachineImpl,

Source

pub fn new<State>(value: T) -> Self
where T::Standin: Initial<State>, State: ConcreteStateTrait,

Creates shared state from a runtime value in an allowed initial state.

State must be a concrete initial state declared by the definition crate. Union markers are intentionally rejected as committed storage states; they can be borrowed as views after a concrete state is stored.

let shared = SArcMutex::<Connection>::new::<Disconnected>(
    Connection::new("localhost:8080"),
);
Source

pub fn from_state<StateMarker>(state: State<SOwned, T, StateMarker>) -> Self
where StateMarker: ConcreteStateTrait,

Moves an owned state token into shared storage without changing state.

This is the shared-storage counterpart to putting an already-created State into Rc, Arc, or another container. The committed runtime marker is taken from the concrete state token.

let disconnected: State<SOwned, Connection, Disconnected> =
    State::new(Connection::new("localhost:8080"));
let shared = SArcMutex::<Connection>::from_state(disconnected);
Source

pub fn borrow<RequestedState>( &self, ) -> Result<SRefView<'_, Backend, T, RuntimeStateMarker<RequestedState>>, SharedStateError<Backend::ReadError<'_, T>>>
where RequestedState: StateTrait + StateMarker + StateRuntimeMarkerFor<<RequestedState as StateMarker>::Kind>, RuntimeStateMarker<RequestedState>: SharedBorrowState,

Borrows the runtime value if the committed state matches RequestedState.

RequestedState may be a concrete state or a generated union marker. Concrete borrows require the exact committed state. Union borrows succeed when the committed concrete state is a member of that union. Errors distinguish “the container could not be borrowed/locked” from “the borrow succeeded but the state was wrong”:

let connected = shared.borrow::<Connected>()?;
let online = shared.borrow::<Online>()?;

match shared.borrow::<Authenticated>() {
    Err(magicstatemachines::SharedStateError::WrongState(error)) => {
        eprintln!("{error}");
    }
    other => { /* storage errors and success are handled separately */ }
}
Source

pub fn borrow_mut<RequestedState>( &self, ) -> Result<SMutView<'_, Backend, T, RuntimeStateMarker<RequestedState>>, SharedStateError<Backend::WriteError<'_, T>>>
where RequestedState: StateTrait + StateMarker + StateRuntimeMarkerFor<<RequestedState as StateMarker>::Kind>, RuntimeStateMarker<RequestedState>: SharedBorrowState,

Mutably borrows the runtime value and tracks the guard’s final state.

When the returned guard is dropped, the shared container is updated to the guard’s pending state. This allows methods on State<SMutView<...>> to retain compile-time transition checks while the committed state is stored at runtime.

{
    let connected = shared.borrow_mut::<Connected>()?;
    let authenticated = transition!(connected, "alice".to_owned());
    drop(authenticated); // commits `Authenticated`.
}

let authenticated = shared.borrow::<Authenticated>()?;

Trait Implementations§

Source§

impl<P: Clone, S: SharedStorage, T> Clone for SharedState<P, S, T>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl<P, S, T> Freeze for SharedState<P, S, T>
where P: Freeze,

§

impl<P, S, T> RefUnwindSafe for SharedState<P, S, T>
where P: RefUnwindSafe,

§

impl<P, S, T> Send for SharedState<P, S, T>
where P: Send,

§

impl<P, S, T> StateClone for SharedState<P, S, T>
where P: StateClone,

§

impl<P, S, T> StateCopy for SharedState<P, S, T>
where P: StateCopy,

§

impl<P, S, T> Sync for SharedState<P, S, T>
where P: Sync,

§

impl<P, S, T> Unpin for SharedState<P, S, T>
where P: Unpin,

§

impl<P, S, T> UnsafeUnpin for SharedState<P, S, T>
where P: UnsafeUnpin,

§

impl<P, S, T> UnwindSafe for SharedState<P, S, T>
where P: 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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.