1.2 KiB
Solution 3: Typestate Pattern using Marker Types
A yet better solution is to utilize the functionality of Rust to be able to do different implementations on a struct depending on type parameters.
We simply introduce two empty marker types Locked and Unlocked. Then, we pass the marker type as type parameter to the CredentialManager struct. Because Rust enforces the usage of type parameters, we need the type parameter to appear in a field for Rust to accept it. We could use state: Locked directly, since Locked is zero-sized and this compiles fine and costs nothing at runtime. But PhantomData<T> is preferred by convention because it decouples the type-level marker from needing an actual constructible value of T, doesn't silently grow the struct's size if T is later changed to something non-zero-sized, and lets you control drop-check/variance/auto-trait behavior independently.
So in this solution, we get the exact same behavior as with the last solution, but with absolutely no extra cost at runtime, which perfectly utilizes the zero cost abstraction principle of Rust.