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>;