rust / expert
Snippet
Compile-Time API State Enforcement using the Typestate Pattern
This snippet implements the Typestate Pattern, which uses Rust's type system to enforce valid transitions of an object at compile time. By consuming `self` during transition methods (such as `connect`), we guarantee that outdated states cannot be reused, preventing runtime logic bugs.
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
27
28
29
30
31
pub struct Uninitialized;pub struct Connected {pub socket_id: u32,}pub struct Connection<State> {pub host: String,pub state: State,}impl Connection<Uninitialized> {pub fn new(host: &str) -> Self {Self {host: host.to_string(),state: Uninitialized,}}pub fn connect(self) -> Connection<Connected> {Connection {host: self.host,state: Connected { socket_id: 101 },}}}impl Connection<Connected> {pub fn send(&self, data: &[u8]) {println!("Sending to socket {}: {:?}", self.state.socket_id, data);}}
Breakdown
1
pub struct Connection<State>
Declares a generic connection type parameterized by its current lifecycle state.
2
impl Connection<Uninitialized>
Implements functions that are only valid when the connection is in the uninitialized state.
3
pub fn connect(self) -> Connection<Connected>
Consumes ownership of `self` (the uninitialized state) and returns a new connection in the connected state.
4
impl Connection<Connected>
Implements functions (like `send`) that are exclusively available after a connection has been successfully established.
5
self.state.socket_id
Accesses data nested inside the `Connected` state structure, which is only present in this state.