# statenum `statenum`, short for "state-enum", is a procedural macro attribute that generates a trait and a struct for each variant of an enum. ## Installation Add the following dependencies to your `Cargo.toml` file: ```toml [dependencies] statenum = "1.0" ``` ## Usage To use `statenum`, add the `#[statenum]` attribute to your enum definition. By default, the generated trait will be named `State`. You can override this by providing a name as an argument to the macro. ```rust use statenum::statenum; #[statenum] enum RocketStage { Grounded, Launched, // and so on... } #[statenum("PayloadState")] enum PayloadStage { Vacant, Packed, // and so on... } ``` ## Visibility This will generate a trait named `State` and a struct for each variant of the enum. The visibility of the enum carries through to the implementation of `statenum`. If the enum is marked as `pub`, the resulting struct variants and trait will also be marked as `pub`. However, if the enum isn't public then neither will the resulting components. ```rust mod hidden { use statenum::statenum; #[statenum] enum RocketStage { Grounded, Launched, } pub struct Rocket { stage: Stage, } } // This would cause an error because the enum `RocketStage` is marked as private. // let grounded: hidden::Rocket; // The same applies to the trait. // trait PayloadState: hidden::State {} ``` ## Examples Normally, the state pattern in Rust requires the use of multiple struct definitions. The example below demonstrates the typical method of implementing the state pattern and is taken from the book 'Rust for Rustaceans' by Jon Gjengset. ```rust use std::marker::PhantomData; struct Grounded; struct Launched; // and so on... pub struct Rocket { stage: PhantomData, } impl Rocket { // ... } impl Rocket { pub fn launch(self) -> Rocket { Rocket:: { stage: PhantomData:: } } } impl Rocket { pub fn accelerate(&mut self) { // ... } pub fn decelerate(&mut self) { // ... } } ``` Using the macro without any trait name specified will create a trait under the name of `State`, like so (intentionally ignoring the `PhantomData` aspect): ```rust use statenum::statenum; #[statenum] enum RocketStage { Grounded, Launched, // and so on... } pub struct Rocket { stage: Stage, } impl Rocket { // ... } impl Rocket { pub fn launch(self) -> Rocket { Rocket:: { stage: Launched } } } impl Rocket { pub fn accelerate(&mut self) { // ... } pub fn decelerate(&mut self) { // ... } } ``` Otherwise, if you would prefer to name the trait something other than `State`, you can accomplish that by specifying a name: ```rust use statenum::statenum; #[statenum("RocketState")] enum RocketStage { Grounded, Launched, // and so on... } pub struct Rocket { stage: Stage, } impl Rocket { // ... } impl Rocket { pub fn launch(self) -> Rocket { Rocket:: { stage: Launched } } } impl Rocket { pub fn accelerate(&mut self) { // ... } pub fn decelerate(&mut self) { // ... } } ``` # License `statenum` is distributed under the terms of the MIT license.