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
//! A simple macro library for creating phantom enums. Just simple sugar. //! //! See the `phantom_enum!` macro for all the details. /// Create a phantom type enum. /// /// A phantom type enum is an enum-like arrangement where the enum is a module /// and trait and the variants are (uninstantiable) types. /// /// This is very good for the static representation of state machines in which /// *nothing* can go wrong. /// /// ```rust /// #[macro_use] #[no_link] /// extern crate phantom_enum; /// /// phantom_enum! { /// /// Put things here, of course /// pub enum TableItem { /// /// A bottle with a paper label reading “DRINK ME”. /// Potion, /// /// A cake with the words “EAT ME” marked in currants. /// Cake, /// } /// } /// /// // Note how this restricts the methods to only meaningful types. /// struct Person<T: TableItem::Impl> { /// name: &'static str, /// phantom: std::marker::PhantomData<T>, /// } /// /// impl<T: TableItem::Impl> Person<T> { /// fn new(name: &'static str) -> Person<T> { /// Person { /// name: name, /// phantom: std::marker::PhantomData, /// } /// } /// } /// /// impl Person<TableItem::Potion> { /// fn drink_it(self) -> Person<TableItem::Cake> { /// println!("Shrinking! Oh look, there’s a box down here!"); /// Person { /// name: self.name, /// phantom: std::marker::PhantomData, /// } /// } /// } /// /// impl Person<TableItem::Cake> { /// fn eat_it(self) -> () { /// println!("Growing! OK, that’s enough of the story."); /// // Who can remember what comes next, anyway? /// } /// } /// /// fn main() { /// let person = Person::new("Alice"); /// let person = person.drink_it(); /// person.eat_it(); /// } /// ``` /// /// As you will observe with this example, if you have a `Person<Potion>`, you /// simply cannot call `.eat_it()`; for that, you must have a `Person<Cake>`. /// Similarly, once you have drunk that potion, you can’t drink it again. #[macro_export] macro_rules! phantom_enum { ( $(#[$enum_attr:meta])* pub enum $name:ident { $( $(#[$variant_attr:meta])+ $variant:ident ),*$(,)* } ) => { $(#[$enum_attr])* #[allow(non_snake_case)] pub mod $name { /// Implemented exclusively by members of this phantom type enum. /// This is for use as a generic bound. pub trait Impl { } $( $(#[$variant_attr])+ #[derive(Copy, Clone)] pub enum $variant { } impl Impl for $variant { } )* } }; ( $(#[$enum_attr:meta])* enum $name:ident { $( $(#[$variant_attr:meta])+ $variant:ident ),*$(,)* } ) => { $(#[$enum_attr])* #[allow(non_snake_case)] mod $name { /// Implemented exclusively by members of this phantom type enum. /// This is for use as a generic bound. pub trait Impl { } $( $(#[$variant_attr])+ #[derive(Copy, Clone)] pub enum $variant { } impl Impl for $variant { } )* } } }