capypad
0 day streak
rust / expert
Snippet

Zero-Cost Typestate Pattern with PhantomData

The Typestate pattern uses Rust's type system to enforce state transitions at compile time. By using PhantomData, we can differentiate states without incurring any runtime memory overhead. This ensures that methods like 'process' can only be called once the data has reached the 'Checked' state.

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
25
26
use std::marker::PhantomData;
 
struct Unchecked;
struct Checked;
 
struct Data<S> {
value: String,
_state: PhantomData<S>,
}
 
impl Data<Unchecked> {
fn new(v: &str) -> Self {
Data { value: v.into(), _state: PhantomData }
}
fn validate(self) -> Data<Checked> {
// Perform complex validation logic here
Data { value: self.value, _state: PhantomData }
}
}
 
impl Data<Checked> {
fn process(&self) {
println!("Processing validated data: {}", self.value);
}
}
Breakdown
1
struct Unchecked;
A zero-sized marker type representing the initial state.
2
_state: PhantomData<S>,
Informs the compiler that Data logically 'owns' a type S without storing it.
3
fn validate(self) -> Data<Checked>
Consumes the current state and returns a new state, making the old one inaccessible.