rust / expert
Snippet
Enforcing State Machine Invariants at Compile-Time using PhantomData
The Type-State Pattern leverages Rust's type system to enforce valid transitions in a state machine at compile-time. By utilizing generic parameters representing the state and PhantomData to satisfy the compiler without runtime overhead, we prevent invalid operations (such as viewing an unpublished post) from even compiling.
snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use std::marker::PhantomData;pub struct Draft;pub struct Published;pub struct Post<State> {content: String,_state: PhantomData<State>,}impl Post<Draft> {pub fn new(content: String) -> Self {Post { content, _state: PhantomData }}pub fn publish(self) -> Post<Published> {Post { content: self.content, _state: PhantomData }}}impl Post<Published> {pub fn view(&self) -> &str {&self.content}}
Breakdown
1
pub struct Post<State> {
Declares a generic struct where State serves as a type-level marker representing the current lifecycle stage of the post.
2
_state: PhantomData<State>,
Instructs the compiler that Post acts as if it owns a value of type State, preventing unused type parameter errors without allocating runtime memory.
3
impl Post<Draft> {
Implements methods that are exclusively available when the Post is in the Draft state.
4
pub fn publish(self) -> Post<Published> {
Consumes the draft post and returns a new post marked with the Published state, preventing further state mutation.