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}