Skip to main content

magicstatemachines/
lib.rs

1#![cfg_attr(
2    all(feature = "decompose", feature = "nightly-random"),
3    feature(random)
4)]
5#![cfg_attr(feature = "unique-rc-arc", feature(unique_rc_arc))]
6#![cfg_attr(not(feature = "gen_no_unsafe"), feature(allow_internal_unsafe))]
7#![feature(
8    arbitrary_self_types,
9    associated_type_defaults,
10    auto_traits,
11    negative_impls
12)]
13#![cfg_attr(not(feature = "gen_no_unsafe"), allow(internal_features))]
14#![cfg_attr(not(feature = "std"), no_std)]
15#![deny(unsafe_code)]
16#![warn(missing_docs)]
17
18//! Ergonomic typestate wrappers for compiler-enforced state machines.
19//!
20//! This crate requires nightly Rust for `arbitrary_self_types`.
21//!
22//! MagicStateMachines lets a state-machine contract live separately from the
23//! runtime type that implements it. A definition crate owns the stand-in type,
24//! state marker ZSTs, initial states, legal transitions, and state unions. An
25//! implementation crate connects a runtime type to that contract with
26//! [`StateMachineImpl!`](macro@crate::StateMachineImpl) and exposes ordinary
27//! inherent methods whose receiver type carries the current state.
28//!
29//! The core receiver type is [`State<Storage, T, S>`], where `T` is the runtime
30//! implementation, `S` is the current state marker, and `Storage` selects how
31//! the runtime value is held. Methods usually constrain storage by capability:
32//! [`SRef`] for read-only access, [`SMut`] for mutable transitions, [`SPinMut`]
33//! for pinned transitions, and [`SMove`] when storage must move by value. This
34//! allows the same state-machine methods to work for owned values, boxes,
35//! pinned boxes, shared guard views, and custom storage backends.
36//!
37//! In the default configuration this crate denies unsafe code. The `dynZST`
38//! feature uses the external `dynzst` crate for thin erased ZST state markers.
39//! Without tracing, directly owned state wrappers are layout-transparent over
40//! the runtime data, and concrete-state transitions are statically dispatched.
41//! When state crosses a boundary the compiler cannot prove, such as shared
42//! storage behind `Rc`, `Arc`, `RefCell`, `Mutex`, or `RwLock`, the committed
43//! erased state is checked at the boundary before returning a typed view.
44//!
45//! State unions support methods over a set of states. A union such as
46//! `Online` generates a sealed membership trait such as `InOnline`, a
47//! discriminated state representation, and an enum such as `OnlineEnum`.
48//! Static union transitions use [`transition!`](macro@crate::transition) with
49//! the `const` form when all members share the same transition body. Dynamic
50//! union transitions use the `dyn` form when the concrete member must be
51//! discriminated first.
52
53#[cfg(feature = "alloc")]
54extern crate alloc;
55
56mod contract;
57#[cfg(feature = "decompose")]
58mod decomposed;
59mod kind;
60mod macros;
61mod policy;
62mod proof;
63mod shared;
64mod state;
65mod state_trait;
66#[cfg(feature = "tracing")]
67/// Transition tracing support.
68///
69/// This module is available with the `tracing` feature. It contains the
70/// [`TraceEntry`] type stored by state wrappers when tracing is enabled.
71pub mod tracing;
72mod union;
73mod util;
74
75pub use contract::{Initial, StateMachineImpl, Transition, TransitionSignature};
76#[cfg(feature = "decompose")]
77pub use decomposed::{DecomposedData, DecomposedState, RecomposeError};
78pub use kind::{
79    ConcreteStateKind, RuntimeStateMarker, StateKind, StateMarker, StateRuntimeMarkerFor,
80    UnionStateKind,
81};
82pub use policy::{StateClone, StateCopy};
83#[doc(hidden)]
84pub use proof::StateUnionTransitionProof;
85#[doc(hidden)]
86pub use proof::UnionTransitionProof;
87pub use proof::{
88    StateConcreteProvenState, StateConcreteTransitionProof, StateProofTransition,
89    StateTransitionProofBind, StateUnionProvenState, StateWithProof, TransitionProof,
90};
91pub use shared::{
92    DynState, DynStorage, RefCellStorage, SMutView, SRefCell, SRefView, SharedBorrowState,
93    SharedState, SharedStateError, SharedStorage, SharedStorageView, SharedValue, StateMut,
94    StateMutTransitionCall, StateRef, StorageStateMut, StorageStateRef, WrongStateError,
95    transition_mut,
96};
97#[cfg(feature = "std")]
98pub use shared::{
99    MutexStorage, RwLockStorage, SArcMutex, SArcRwLock, SMutex, SRwLock, WeakSArcMutex,
100    WeakSArcRwLock,
101};
102#[cfg(feature = "alloc")]
103pub use shared::{SArc, SRc, SRcRefCell, WeakSArc, WeakSRc, WeakSRcRefCell};
104pub use state::{
105    ConcreteProofTransitionCall, ConcreteStated, DiscriminatedTransitionCall, EffectTransitionCall,
106    InferenceKind, InnerInference, InnerStateInference, KindProofTransitionCall, MayTransition,
107    OuterInference, PinnedDiscriminatedTransitionCall, PinnedEffectTransitionCall,
108    PinnedStateUnionProofTransitionCall, PinnedTransitionEffect, PinnedTransitionEffectSelector,
109    SMapRuntime, SMove, SMut, SOwned, SPin, SPinMut, SPinRef, SRef, SResult, State, StateInference,
110    StateOwned, StateStorage, StateStorageNew, StateTransitionCall, StateUnionProofTransitionCall,
111    StorageStateOwned, TransitionCall, TransitionCallsite, TransitionEffect,
112    TransitionEffectSelector, complete_transition_after_effect, pin_mut, pin_ref, proven_state,
113    proven_union_state, transition, transition_callsite, transition_concrete_after_effect,
114    transition_concrete_after_pinned_effect, transition_discriminated_state,
115    transition_discriminated_state_pinned, transition_state,
116    transition_state_with_concrete_kind_proof, transition_state_with_concrete_proof,
117    transition_state_with_concrete_transition_proof, transition_state_with_effect,
118    transition_state_with_erased_transition_proof, transition_state_with_kind_proof,
119    transition_state_with_pinned_effect, transition_state_with_static_union_pinned_proof,
120    transition_state_with_static_union_proof, transition_state_with_union_proof,
121    transition_state_with_union_transition_proof,
122};
123#[cfg(feature = "alloc")]
124pub use state::{SBox, SPinBox, StorageStateOwnedBox, StorageStateOwnedPinBox};
125#[cfg(all(feature = "std", feature = "unique-rc-arc"))]
126pub use state::{StorageStateOwnedUniqueArc, StorageStateOwnedUniqueRc};
127#[doc(hidden)]
128pub use state_trait::ConcreteStateTrait;
129pub use state_trait::StateTrait;
130#[doc(hidden)]
131pub use state_trait::{ErasedState, clone_erased as clone_erased_state};
132#[cfg(feature = "tracing")]
133pub use tracing::TraceEntry;
134#[doc(hidden)]
135pub use union::StateUnionConcreteState;
136#[doc(hidden)]
137pub use union::StateUnionDiscriminatedPinnedTransition;
138#[doc(hidden)]
139pub use union::StateUnionDiscriminatedTransition;
140#[doc(hidden)]
141pub use union::{
142    DiscriminatedInner, SDiscriminated, StateUnionErased, StateUnionMember,
143    StateUnionProofMembership, StateUnionProofTarget, StateUnionRuntime, StateUnionSharedEffect,
144    StateUnionSharedPinnedEffect, StateUnionSharedPinnedTransitionEffect,
145    StateUnionSharedTransitionEffect, StateUnionState, StateUnionTransition,
146    concretize_discriminated_state, discriminate_state, discriminated_state_marker,
147    erased_state_type_id, rediscriminate_union_state, state_union_marker, undiscriminate_state,
148};
149pub use union::{DiscriminatedState, In, StateUnionDiscriminant};
150pub use util::EnumExt;
151
152#[doc(hidden)]
153pub mod __private {
154    pub use crate::state::concrete_stated_new;
155    pub use paste::paste;
156}
157
158#[cfg(test)]
159mod tests;