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. That declaration is a public constructor contract: anyone with raw T can create State<SOwned, T, S> for an initial state. States that should only be entered by target-owned conversions should not be listed as Initial.

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

pub fn from_concrete(value: ConcreteStated<T, S>) -> Self
where S: ConcreteStateTrait,

Constructs a directly owned state from implementation-owned state proof.

ConcreteStated is where the unsafe or private raw construction decision happens. This function only consumes that proof object and creates the ordinary owned state wrapper.

Source

pub fn into_concrete(state: Self) -> ConcreteStated<T, S>
where S: ConcreteStateTrait,

Consumes a directly owned state and returns raw data plus its concrete marker.

This is intended for implementation-owned conversions. The returned value can be inspected only by consuming it with ConcreteStated::into_raw.

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.