Skip to main content

magicstatemachines/
kind.rs

1use crate::{
2    StateMachineImpl, StateStorage, StateTrait, StateUnionDiscriminant, StateUnionState,
3    StateUnionTransitionProof, TransitionProof,
4};
5
6/// Classifies state marker types.
7///
8/// End users usually interact with this indirectly through [`States!`](macro@crate::States) and
9/// [`StateUnion!`](macro@crate::StateUnion). Concrete states use [`ConcreteStateKind`], while generated
10/// union markers use [`UnionStateKind`].
11///
12/// The kind is what lets generic transition helpers choose different proof
13/// machinery without exposing separate public transition methods. A concrete
14/// state proves transitions directly from `From -> To`. A union marker proves
15/// transitions through the generated union membership/discrimination logic.
16///
17/// You normally do not implement this trait. If you need custom state markers,
18/// prefer wrapping them in [`States!`](macro@crate::States) so the marker kind,
19/// erased-state support, and ZST invariants are all wired consistently.
20pub trait StateKind: Sized {
21    /// Runtime marker actually checked by shared storage for this kind.
22    ///
23    /// Concrete states resolve to themselves. Union markers resolve to their
24    /// generated joint [`StateUnionState`].
25    type RuntimeState<Marker>: StateTrait + StateMarker
26    where
27        Marker: StateRuntimeMarkerFor<Self>;
28
29    /// Proof type used by generated transition helpers for this kind.
30    ///
31    /// This associated type lets the macro-generated transition code select
32    /// concrete-state proof logic or union-state proof logic without exposing
33    /// separate public methods.
34    type Proof<T, From, Marker, To>
35    where
36        T: StateMachineImpl,
37        From: StateTrait + StateMarker<Kind = Self>,
38        Marker: StateUnionDiscriminant,
39        To: StateTrait + StateMarker<Kind = ConcreteStateKind>;
40
41    #[doc(hidden)]
42    #[must_use]
43    fn prove<Storage, T, From, Marker, To>() -> TransitionProof<Storage, T, From, Marker, To, Self>
44    where
45        Storage: StateStorage,
46        T: StateMachineImpl,
47        From: StateTrait + StateMarker<Kind = Self>,
48        Marker: StateUnionDiscriminant,
49        To: StateTrait + StateMarker<Kind = ConcreteStateKind>,
50    {
51        TransitionProof::new()
52    }
53}
54
55/// Marker kind for concrete state ZSTs.
56///
57/// This is the kind assigned by [`States!`](macro@crate::States). Concrete
58/// states can be stored as the authoritative state in shared storage and can
59/// appear as concrete transition sources or targets.
60pub struct ConcreteStateKind;
61
62impl StateKind for ConcreteStateKind {
63    type RuntimeState<Marker>
64        = <Marker as StateRuntimeMarkerFor<Self>>::RuntimeState
65    where
66        Marker: StateRuntimeMarkerFor<Self>;
67
68    type Proof<T, From, Marker, To>
69        = crate::StateConcreteTransitionProof<T, From, Marker, To>
70    where
71        T: StateMachineImpl,
72        From: StateTrait + StateMarker<Kind = Self>,
73        Marker: StateUnionDiscriminant,
74        To: StateTrait + StateMarker<Kind = ConcreteStateKind>;
75}
76
77/// Marker kind for generated union state markers.
78///
79/// This is the kind assigned by [`StateUnion!`](macro@crate::StateUnion).
80/// Union markers are accepted as borrowed views and generic receiver bounds,
81/// but they are not valid committed states in shared storage. Shared storage
82/// commits the concrete member marker and checks union borrows against it.
83pub struct UnionStateKind;
84
85impl StateKind for UnionStateKind {
86    type RuntimeState<Marker>
87        = <Marker as StateRuntimeMarkerFor<Self>>::RuntimeState
88    where
89        Marker: StateRuntimeMarkerFor<Self>;
90
91    type Proof<T, From, Marker, To>
92        = StateUnionTransitionProof<T, From, Marker, To>
93    where
94        T: StateMachineImpl,
95        From: StateTrait + StateMarker<Kind = Self>,
96        Marker: StateUnionDiscriminant,
97        To: StateTrait + StateMarker<Kind = ConcreteStateKind>;
98}
99
100/// Common trait implemented by concrete states and generated union markers.
101///
102/// Concrete state ZSTs generated by [`States!`](macro@crate::States) implement this with
103/// [`ConcreteStateKind`]. Union markers generated by [`StateUnion!`](macro@crate::StateUnion) implement
104/// it with [`UnionStateKind`].
105///
106/// Manual implementations are advanced API. The implementation must be a ZST
107/// marker and must return a stable erased marker for concrete states. This is
108/// why the recommended definition-crate pattern is:
109///
110/// ```ignore
111/// pub mod states {
112///     magicstatemachines::States! {
113///         /// The machine is idle.
114///         Idle;
115///         /// The machine is running.
116///         Running;
117///     }
118/// }
119/// ```
120pub trait StateMarker: 'static {
121    /// Whether this marker is a concrete state or a union marker.
122    type Kind: StateKind;
123
124    #[doc(hidden)]
125    fn erased_state() -> &'static dyn StateTrait
126    where
127        Self: Sized;
128}
129
130impl<Marker> StateMarker for StateUnionState<Marker>
131where
132    Marker: StateUnionDiscriminant + 'static,
133{
134    type Kind = UnionStateKind;
135
136    fn erased_state() -> &'static dyn StateTrait {
137        panic!("union state markers cannot be stored as ErasedState")
138    }
139}
140
141#[doc(hidden)]
142pub trait StateRuntimeMarkerFor<Kind: StateKind>: StateTrait + StateMarker {
143    type RuntimeState: StateTrait + StateMarker;
144}
145
146impl<Marker> StateRuntimeMarkerFor<ConcreteStateKind> for Marker
147where
148    Marker: StateTrait + StateMarker<Kind = ConcreteStateKind>,
149{
150    type RuntimeState = Marker;
151}
152
153impl<Marker> StateRuntimeMarkerFor<UnionStateKind> for Marker
154where
155    Marker: StateUnionDiscriminant + StateTrait,
156    StateUnionState<Marker>: StateTrait,
157{
158    type RuntimeState = StateUnionState<Marker>;
159}
160
161/// Runtime marker used when borrowing `Marker` from shared storage.
162///
163/// For concrete states this is `Marker`. For union markers this is the
164/// generated joint [`StateUnionState<Marker>`].
165///
166/// This alias is mostly visible in shared-storage return types. For example,
167/// `shared.borrow::<Connected>()` returns an immutable
168/// `State<StorageStateRef<...>, T, Connected>` view, while
169/// `shared.borrow::<Online>()` returns an immutable
170/// `State<StorageStateRef<...>, T, StateUnionState<Online>>` view.
171pub type RuntimeStateMarker<Marker> =
172    <<Marker as StateMarker>::Kind as StateKind>::RuntimeState<Marker>;