1#![doc = include_str!("../README.md")]
2#[macro_export]
4macro_rules! typestate_enum {
5 (@elem
6 $vis:vis $name:ident {
7 $(#[$meta:meta])*
8 $elem:ident,
9 $(
10 $(#[$tail_meta:meta])*
11 $elems:ident
12 ),+
13 }
14 ) => {
15 typestate_enum!(@elem
16 $vis $name {
17 $(#[$meta])*
18 $elem
19 }
20 );
21 typestate_enum!(@elem
22 $vis $name {
23 $(
24 $(#[$tail_meta])*
25 $elems
26 ),+
27 }
28 );
29 };
30 (@elem
31 $vis:vis $name:ident {
32 $(#[$meta:meta])*
33 $elem:ident
34 }
35 ) => {
36 $(#[$meta])*
37 $vis struct $elem;
38 impl $name for $elem {}
39 };
40 (
41 $(#[$outer_meta:meta])*
42 $vis:vis $name:ident {
43 $(
44 $(#[$inner_meta:meta])*
45 $elems:ident
46 ),+
47 $(,)?
48 }
49 ) => {
50 $(#[$outer_meta])*
51 $vis trait $name {}
52
53 typestate_enum!(@elem
54 $vis $name {
55 $(
56 $(#[$inner_meta])*
57 $elems
58 ),+
59 }
60 );
61 };
62}
63
64#[cfg(test)]
65mod test {
66 use super::typestate_enum;
67 use std::marker::PhantomData;
68
69 typestate_enum! {
70 pub State {
71 Ready,
72 Working,
73 Complete
74 }
75 }
76
77 struct Action<S: State>(PhantomData<S>);
78
79 impl<S: State> Action<S> {
80 fn new() -> Self {
81 Action::<S>(PhantomData)
82 }
83 }
84
85 impl Action<Ready> {
86 fn start_work(self) -> Action<Working> {
87 Action::new()
88 }
89 }
90
91 impl Action<Working> {
92 fn complete_work(self) -> Action<Complete> {
93 Action::new()
94 }
95 }
96
97 impl Action<Complete> {}
98
99 #[test]
100 fn test_typestate_enum() {
101 let ready_action = Action::<Ready>::new();
102 let working_action = ready_action.start_work();
103 working_action.complete_work();
104 }
105}