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