Skip to main content

statum_core/
lib.rs

1//! Core traits and helper types shared by Statum crates.
2//!
3//! Most users reach these through the top-level `statum` crate. This crate
4//! holds the small runtime surface that macro-generated code targets:
5//!
6//! - state marker traits
7//! - transition capability traits
8//! - runtime error and result types
9//! - projection helpers for event-log style rebuilds
10
11#[cfg(doctest)]
12#[doc = include_str!("../README.md")]
13mod readme_doctests {}
14
15mod introspection;
16
17pub mod projection;
18
19#[doc(hidden)]
20pub mod __private {
21    pub use linkme;
22
23    #[derive(Debug)]
24    pub struct TransitionToken {
25        _private: u8,
26    }
27
28    impl Default for TransitionToken {
29        fn default() -> Self {
30            Self::new()
31        }
32    }
33
34    impl TransitionToken {
35        pub const fn new() -> Self {
36            Self { _private: 0 }
37        }
38    }
39}
40
41pub use introspection::{
42    MachineDescriptor, MachineGraph, MachineIntrospection, MachinePresentation,
43    MachinePresentationDescriptor, MachineStateIdentity, MachineTransitionRecorder,
44    RecordedTransition, StateDescriptor, StatePresentation, TransitionDescriptor,
45    TransitionInventory, TransitionPresentation,
46};
47
48/// A generated state marker type.
49///
50/// Every `#[state]` variant produces one marker type that implements
51/// `StateMarker`. The associated `Data` type is `()` for unit states and the
52/// tuple payload type for data-bearing states.
53pub trait StateMarker {
54    /// The payload type stored in machines for this state.
55    type Data;
56}
57
58/// A generated state marker with no payload.
59///
60/// Implemented for unit state variants like `Draft` or `Published`.
61pub trait UnitState: StateMarker<Data = ()> {}
62
63/// A generated state marker that carries payload data.
64///
65/// Implemented for tuple variants like `InReview(Assignment)`.
66pub trait DataState: StateMarker {}
67
68/// A machine that can transition directly to `Next`.
69///
70/// This is the stable trait-level view of `self.transition()`.
71pub trait CanTransitionTo<Next> {
72    /// The transition result type.
73    type Output;
74
75    /// Perform the transition.
76    fn transition_to(self) -> Self::Output;
77}
78
79/// A machine that can transition using `Data`.
80///
81/// This is the stable trait-level view of `self.transition_with(data)`.
82pub trait CanTransitionWith<Data> {
83    /// The next state selected by this transition.
84    type NextState;
85    /// The transition result type.
86    type Output;
87
88    /// Perform the transition with payload data.
89    fn transition_with_data(self, data: Data) -> Self::Output;
90}
91
92/// A machine that can transition by mapping its current state data into `Next`.
93///
94/// This is the stable trait-level view of `self.transition_map(...)`.
95pub trait CanTransitionMap<Next: StateMarker> {
96    /// The payload type stored in the current state.
97    type CurrentData;
98    /// The transition result type.
99    type Output;
100
101    /// Perform the transition by consuming the current state data and producing the next payload.
102    fn transition_map<F>(self, f: F) -> Self::Output
103    where
104        F: FnOnce(Self::CurrentData) -> Next::Data;
105}
106
107/// Errors returned by Statum runtime helpers.
108#[derive(Debug)]
109pub enum Error {
110    /// Returned when a runtime check determines the current state is invalid.
111    InvalidState,
112}
113
114/// Convenience result alias used by Statum APIs.
115///
116/// # Example
117///
118/// ```
119/// fn ensure_ready(ready: bool) -> statum_core::Result<()> {
120///     if ready {
121///         Ok(())
122///     } else {
123///         Err(statum_core::Error::InvalidState)
124///     }
125/// }
126///
127/// assert!(ensure_ready(true).is_ok());
128/// assert!(ensure_ready(false).is_err());
129/// ```
130pub type Result<T> = core::result::Result<T, Error>;
131
132impl<T> From<Error> for core::result::Result<T, Error> {
133    fn from(val: Error) -> Self {
134        Err(val)
135    }
136}
137
138impl core::fmt::Display for Error {
139    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
140        write!(fmt, "{self:?}")
141    }
142}
143
144impl std::error::Error for Error {}