As our lives become increasingly more reliant on software, the impact of its failures grows as well; these failures have diverse causes and their impact ranges from negligible to life-threatening; thus, it is our duty as developers to minimize their occurrence, just as other fields do. To that end, we build abstractions, move complexity from component to component, and much more, just to stop the end-user from shooting themselves in the foot. However, building said abstractions still requires the original author to know where the pitfalls lie and how to avoid them, an implicit contract that does not constitute a guarantee that they will not shoot themselves and their users in the feet. Rust aims to minimize the amount of handguns users have at their disposal, locking them behind special unsafe blocks and restricting the set of possible programs through static analysis; this analysis is performed by the compiler which ensures that the program does not contain memory related errors such as use-after-free bugs. While Rust is able to succeed in the previous domain, other error classes persist, such as errors related to API misusage. Our work aims to tackle that domain, providing a tool which enables developers to write safer APIs using typestates. We propose a macro which embeds a typestate description DSL in Rust which allows developers to specify typestates for their APIs; the typestate is checked at compile-time for common mistakes and to ensure the correct usage of the typestate, we leverage Rust's type system. Our work only requires a Rust compiler, avoiding workflow bloat and keeping the development experience simple; it is open-source and available at https://github.com/rustype/typestate-rs.
- Behavioral types