phantom_enum/
lib.rs

1//! A simple macro library for creating phantom enums. Just simple sugar.
2//!
3//! See the `phantom_enum!` macro for all the details.
4
5/// Create a phantom type enum.
6///
7/// A phantom type enum is an enum-like arrangement where the enum is a module
8/// and trait and the variants are (uninstantiable) types.
9///
10/// This is very good for the static representation of state machines in which
11/// *nothing* can go wrong.
12///
13/// ```rust
14/// #[macro_use] #[no_link]
15/// extern crate phantom_enum;
16///
17/// phantom_enum! {
18///     /// Put things here, of course
19///     pub enum TableItem {
20///         /// A bottle with a paper label reading “DRINK ME”.
21///         Potion,
22///         /// A cake with the words “EAT ME” marked in currants.
23///         Cake,
24///     }
25/// }
26///
27/// // Note how this restricts the methods to only meaningful types.
28/// struct Person<T: TableItem::Impl> {
29///     name: &'static str,
30///     phantom: std::marker::PhantomData<T>,
31/// }
32///
33/// impl<T: TableItem::Impl> Person<T> {
34///     fn new(name: &'static str) -> Person<T> {
35///         Person {
36///             name: name,
37///             phantom: std::marker::PhantomData,
38///         }
39///     }
40/// }
41///
42/// impl Person<TableItem::Potion> {
43///     fn drink_it(self) -> Person<TableItem::Cake> {
44///         println!("Shrinking! Oh look, there’s a box down here!");
45///         Person {
46///             name: self.name,
47///             phantom: std::marker::PhantomData,
48///         }
49///     }
50/// }
51///
52/// impl Person<TableItem::Cake> {
53///     fn eat_it(self) -> () {
54///         println!("Growing! OK, that’s enough of the story.");
55///         // Who can remember what comes next, anyway?
56///     }
57/// }
58///
59/// fn main() {
60///     let person = Person::new("Alice");
61///     let person = person.drink_it();
62///     person.eat_it();
63/// }
64/// ```
65///
66/// As you will observe with this example, if you have a `Person<Potion>`, you
67/// simply cannot call `.eat_it()`; for that, you must have a `Person<Cake>`.
68/// Similarly, once you have drunk that potion, you can’t drink it again.
69#[macro_export]
70macro_rules! phantom_enum {
71    (
72        $(#[$enum_attr:meta])*
73        pub enum $name:ident {
74            $(
75                $(#[$variant_attr:meta])+
76                $variant:ident
77             ),*$(,)*
78        }
79    ) => {
80        $(#[$enum_attr])*
81        #[allow(non_snake_case)]
82        pub mod $name {
83            /// Implemented exclusively by members of this phantom type enum.
84            /// This is for use as a generic bound.
85            pub trait Impl { }
86
87            $(
88                $(#[$variant_attr])+
89                #[derive(Copy, Clone)]
90                pub enum $variant { }
91                impl Impl for $variant { }
92            )*
93        }
94    };
95
96    (
97        $(#[$enum_attr:meta])*
98        enum $name:ident {
99            $(
100                $(#[$variant_attr:meta])+
101                $variant:ident
102             ),*$(,)*
103        }
104    ) => {
105        $(#[$enum_attr])*
106        #[allow(non_snake_case)]
107        mod $name {
108            /// Implemented exclusively by members of this phantom type enum.
109            /// This is for use as a generic bound.
110            pub trait Impl { }
111
112            $(
113                $(#[$variant_attr])+
114                #[derive(Copy, Clone)]
115                pub enum $variant { }
116                impl Impl for $variant { }
117            )*
118        }
119    }
120}