Skip to main content

State

Struct State 

Source
pub struct State<Storage, T, S>
where T: StateMachineImpl, Storage: StateStorage,
{ /* private fields */ }
Expand description

A state token parameterized by storage, runtime implementation, and state.

The type parameters carry the whole proof:

  • Storage selects how the runtime value is held, for example SOwned, StorageStateOwnedBox, or a mutable guard from shared storage.
  • T is the runtime implementation type, such as Connection.
  • S is the current state marker, such as Disconnected or impl InOnline.

State is intentionally a deref-like wrapper with very few inherent methods. State-machine behavior should be implemented on T with arbitrary self types, not added as generic convenience methods on State. That keeps the transition capability private to the implementation module.

impl Connection {
    fn connect<S>(self: State<S, Self, Disconnected>) -> State<S, Self, Connected>
    where
        S: SMut,
    {
        magicstatemachines::transition!(self)
    }

    fn endpoint<S>(self: &State<S, Self, impl InOnline>) -> &str
    where
        S: SRef,
    {
        &self.endpoint
    }
}

Implementations§

Source§

impl<T, S> State<StorageStateOwned, T, S>

Source

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

Wraps an implementation in an initial directly owned state.

This is the normal entry point for a state machine. It only compiles when the definition crate declared S as an initial state for T::Standin.

use magicstatemachines::{SOwned, State};
use test_def::states::Disconnected;

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

To move the state into another owned container later, create that container from the returned state token instead of constructing raw T again.

Source§

impl<T, S> State<StorageStateOwnedBox, T, S>

Source

pub fn new(state: State<StorageStateOwned, T, S>) -> Self

Moves a directly owned state into Box storage without changing its state.

This mirrors Box::new, but it takes State<SOwned, T, S> instead of raw T so the current state is preserved:

let owned: State<SOwned, Connection, Connected> = connection.connect();
let boxed: SBox<Connection, Connected> = SBox::new(owned);
Source

pub fn unbox(state: Self) -> State<StorageStateOwned, T, S>

Moves this boxed state back into direct owned storage.

This consumes the box and returns State<SOwned, T, S>. The state marker is unchanged, so methods available before boxing remain available after unboxing.

let boxed: SBox<Connection, Connected> = SBox::new(owned);
let owned_again: State<SOwned, Connection, Connected> = SBox::unbox(boxed);
Source§

impl<T, S> State<StorageStateOwnedPinBox, T, S>

Source

pub fn new(state: State<StorageStateOwnedBox, T, S>) -> Self

Pins an already boxed state in place without changing its state.

Pinning must happen to the boxed allocation. For that reason this constructor consumes SBox rather than SOwned:

let boxed: SBox<Connection, Connected> = SBox::new(owned);
let pinned: SPinBox<Connection, Connected> = SPinBox::new(boxed);
Source

pub fn into_boxed(state: Self) -> State<StorageStateOwnedBox, T, S>
where T: Unpin,

Converts pinned box storage back to box storage when the runtime is Unpin.

This is only available for T: Unpin; otherwise the pinning guarantee must be preserved.

use core::marker::PhantomPinned;
use magicstatemachines::{
    Initial, SBox, SOwned, SPinBox, State, StateMachineImpl, States,
};

struct Machine;
struct Runtime {
    _pin: PhantomPinned,
}
struct Token;

States! {
    Ready;
}

impl Initial<Ready> for Machine {}

impl StateMachineImpl for Runtime {
    type Standin = Machine;
    type Impl = Self;
    type TransitionToken = Token;
}

let ready = State::<SOwned, _, Ready>::new(Runtime {
    _pin: PhantomPinned,
});
let pinned: SPinBox<Runtime, Ready> = SPinBox::new(SBox::new(ready));

// `Runtime` is `!Unpin`, so the pinned allocation cannot be turned
// back into an ordinary box.
let _boxed = SPinBox::into_boxed(pinned);
Source§

impl<Storage, T, Marker> State<SDiscriminated<Storage>, T, StateUnionState<Marker>>

Source

pub fn discriminate( self, ) -> <Marker as StateUnionDiscriminant>::Enum<Storage, T>

Recovers the generated enum for this discriminated union state.

This is the runtime branch point: after matching on the enum, each variant can be converted back into its concrete state.

match online.discriminate() {
    OnlineEnum::Connected(connected) => {
        let authenticated = connected.authenticate("alice");
    }
    OnlineEnum::Authenticated(authenticated) => {
        let connected = authenticated.logout();
    }
}

Trait Implementations§

Source§

impl<Storage, T, S> Deref for State<Storage, T, S>
where T: StateMachineImpl, Storage: SRef,

Source§

type Target = T

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.
Source§

impl<Storage, T, S> DerefMut for State<Storage, T, S>
where T: StateMachineImpl, Storage: SMut,

Source§

fn deref_mut(&mut self) -> &mut Self::Target

Mutably dereferences the value.

Auto Trait Implementations§

§

impl<Storage, T, S> Freeze for State<Storage, T, S>
where <Storage as StateStorage>::Inner<T, S>: Freeze,

§

impl<Storage, T, S> RefUnwindSafe for State<Storage, T, S>
where <Storage as StateStorage>::Inner<T, S>: RefUnwindSafe,

§

impl<Storage, T, S> Send for State<Storage, T, S>
where <Storage as StateStorage>::Inner<T, S>: Send,

§

impl<Storage, T, S> StateClone for State<Storage, T, S>
where <Storage as StateStorage>::Inner<T, S>: StateClone,

§

impl<Storage, T, S> StateCopy for State<Storage, T, S>
where <Storage as StateStorage>::Inner<T, S>: StateCopy,

§

impl<Storage, T, S> Sync for State<Storage, T, S>
where <Storage as StateStorage>::Inner<T, S>: Sync,

§

impl<Storage, T, S> Unpin for State<Storage, T, S>
where <Storage as StateStorage>::Inner<T, S>: Unpin,

§

impl<Storage, T, S> UnsafeUnpin for State<Storage, T, S>
where <Storage as StateStorage>::Inner<T, S>: UnsafeUnpin,

§

impl<Storage, T, S> UnwindSafe for State<Storage, T, S>
where <Storage as StateStorage>::Inner<T, S>: 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<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
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.