1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//!
//! # 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: State = Grounded> {
//! stage: Stage,
//! }
//! }
//!
//! // This would cause an error because the enum `RocketStage` is marked as private.
//! // let grounded: hidden::Rocket<hidden::Grounded>;
//!
//! // 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 = Grounded> {
//! stage: PhantomData<Stage>,
//! }
//!
//! impl<Stage> Rocket<Stage> {
//! // ...
//! }
//!
//! impl Rocket<Grounded> {
//! pub fn launch(self) -> Rocket<Launched> {
//! Rocket::<Launched> { stage: PhantomData::<Launched> }
//! }
//! }
//!
//! impl Rocket<Launched> {
//! 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: State = Grounded> {
//! stage: Stage,
//! }
//!
//! impl<Stage: State> Rocket<Stage> {
//! // ...
//! }
//!
//! impl Rocket<Grounded> {
//! pub fn launch(self) -> Rocket<Launched> {
//! Rocket::<Launched> { stage: Launched }
//! }
//! }
//!
//! impl Rocket<Launched> {
//! 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: RocketState = Grounded> {
//! stage: Stage,
//! }
//!
//! impl<Stage: RocketState> Rocket<Stage> {
//! // ...
//! }
//!
//! impl Rocket<Grounded> {
//! pub fn launch(self) -> Rocket<Launched> {
//! Rocket::<Launched> { stage: Launched }
//! }
//! }
//!
//! impl Rocket<Launched> {
//! pub fn accelerate(&mut self) {
//! // ...
//! }
//!
//! pub fn decelerate(&mut self) {
//! // ...
//! }
//! }
//! ```
//!
//! # License
//!
//! `statenum` is distributed under the terms of the MIT license.
//!
// private imports...
use *;
use *;
/// `statenum` is a procedural macro attribute that generates a trait and a struct for each variant of an enum.
/// The generated trait is named `State` by default, but this can be overridden by providing a name as an argument to the macro.
/// Each generated struct has the same visibility as the original enum.
///
/// # Arguments
///
/// * `args: TokenStream` - The arguments provided to the macro. This should be a string literal containing the name of the generated trait.
/// * `item: TokenStream` - The item that the macro was invoked on. This should be an enum.
///
/// # Panics
///
/// This function will panic if the `item` is not an enum.
///