Still, it's a great pattern that I use as often as I can!
An interface with multiple implementations.
The typesstate pattern felt hostile when libs using it only included examples of use directly in a main function where you didn't have to specify the type; you'd try to use them in a program in a struct field, function signature etc, and wouldn't know what type to put in.
Example of typestates I've seen: `Spi<SPI1, PA5<Alternate<AF11>>, PA6<Alternate<AF69>...>>>>>>>`
When would be easier to use a plain `Spi` struct.
These aren't necessarily critiques of the typestate pattern in general, but those are the 2 points that pushed me away from it.
In the function signature, Rust deliberately doesn't have inference, you must write down the types and decltype would not be acceptable for that purpose.
(I wouldn’t count impl trait in function parameters since that acts more like a generic type.)
The compiler knows which concrete type it is, but you needn't and your caller isn't promised it is any particular type (but it is, they just aren't allowed to care)
This is useful because all Rust's functions are types, both lambda and ordinary functions are unique types, but we often want to say I'm going to return say a predicate - we can't name the predicate we're going to return but our caller just wants a predicate so they don't care that we couldn't spell its name.
https://github.com/tim-group/higher-kinded-lifecycle/blob/ma...
This is where you can index the different constructors (enum variants) with an additional type variables and even specialize them when needed. A pretty powerful tool to encode at the type level that similar things are slightly different.
I've been a huge fan of the type-state pattern [1]. I don't see it mentioned often, and never outside of Rust so far. However, it's applicable to most languages, including ones you wouldn't suspect (Python). If you introduce a whole new type (not a big deal in Rust; more of a ceremony in C# et al.) for `DeletedUser`, you can simply leave off the `active` function! Any action (==state transition) on that type will be legal and possible. Methods have unit value return type, no `Result` needed. You cannot handle that incorrectly! The code won't even compile.
I am still in the process of exploring downsides to the pattern. For example, in classic OOP languages, you can create a type hierarchy, with a top-level `User`, and the different kinds inheriting from it (and then ideally be marked `final`/`sealed` or whatever). You can then treat all users the same by interacting with the top-level type. Useful for DB interaction, for example. The same in Rust would go through traits: `impl User for DeletedUser`. But it's not quite as nice, is it?
1: https://cliffle.com/blog/rust-typestate/