liveBook · Manning

Finite-state machine

As explained in Idiomatic Rust

A state machine is a computational model whose behavior changes according to its current state and explicitly defined transitions.

A finite-state machine models a system as named states and permitted transitions between them. In Rust, traits and generics can make those rules part of the type system: a method available in one state need not exist in another. section 8.1

Consider a user session with Initial, Anonymous, Authenticated, and LoggedOut states. Define each state as a marker type implementing SessionState, then tag Session<State> with PhantomData<State>. The session still carries its ID and properties; its type also identifies which operations are valid. section 8.1

Listing 8.1 Modeling session state with traits and struct tagging
pub trait SessionState {}

#[derive(Debug, Default)]
pub struct Session<State: SessionState = Initial> {     #1
    session_id: Uuid,
    props: HashMap<String, String>,     #2
    phantom: PhantomData<State>,
}

#[derive(Debug, Default)]
pub struct Initial;
#[derive(Debug, Default)]
pub struct Anonymous;
#[derive(Debug, Default)]
pub struct Authenticated;
#[derive(Debug, Default)]
pub struct LoggedOut;

impl SessionState for Initial {}
impl SessionState for Anonymous {}
impl SessionState for Authenticated {}
impl SessionState for LoggedOut {}

The listing shows the marker types, their shared trait, and the generic Session structure that ties a session value to a state. section 8.1

Authenticate, update, log out

Session::new() creates an anonymous session. authenticate(self, username, password) returns either Session<Authenticated> or the original Session<Anonymous> on failure. Only the authenticated implementation provides update_property and logout; logout consumes that session and returns Session<LoggedOut>. The example credential check is deliberately simple, and resuming an ID omits the database lookup and validation a real session would need. section 8.1

Use this pattern when state-specific operations make a stateful system hard to reason about. It is not a panacea, but small, type-safe machines can rule out invalid transitions before the program runs. Coroutines show a related use of the model: the Rust compiler tracks whether a coroutine has started, yielded, or completed. section 8.1 section 8.2

How Idiomatic Rust covers it

How deep it goes
Works through marker types, a generic session, and transition methods; leaves real session-ID lookup and validation unimplemented.
Examples
Uses an anonymous-to-authenticated user session with property updates and logout, plus a coroutine that yields before completing.
What it assumes
Assumes familiarity with Rust traits and generics, then builds the session model from named states.
What you can do after
Build it from scratch using Rust marker types and state-specific methods to restrict session transitions at compile time.
How it connects
Connects state machines to Rust traits, generics, PhantomData, ownership-consuming methods, and compiler-generated coroutine states.

Also explained in

Compare how 9 books explain finite-state machine →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Idiomatic Rust. The section links point to the parts of the book it draws on.