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
//! # Enum Ordinalize
//! This crates provides `ordinalize_enum` and `create_ordinalized_enum` macros to let enums can not only get its variants' ordinal but also be constructed with an ordinal.
//!
//! ## Make an Enum Ordinalized
//!
//! `ordinalize_enum` macro can implement a `ordinal` method and a `from_ordinal` associated function for an existing `enum`.
//!
//! ```
//! #[macro_use] extern crate enum_ordinalize;
//!
//! #[derive(Debug, PartialEq)]
//! enum MyEnum {
//!     Zero,
//!     One,
//!     Two,
//! }
//!
//! ordinalize_enum!(MyEnum,
//!     u8,
//!     Zero,
//!     One,
//!     Two
//! );
//!
//! assert_eq!(2, MyEnum::Two.ordinal());
//! assert_eq!(Some(MyEnum::One), MyEnum::from_ordinal(1));
//! ```
//!
//! ## Create an Ordinalized Enum
//!
//! `create_ordinalized_enum` macro can create an enum and implement a `ordinal` method and a `from_ordinal` associated function for it.
//! The new enum also implements `Debug`, `PartialEq`, and `Clone` traits.
//!
//! ```
//! #[macro_use] extern crate enum_ordinalize;
//!
//! create_ordinalized_enum!(MyEnum,
//!     u8,
//!     Zero,.travis.yml
//appveyor.yml
//LICENSE
//!     One,
//!     Two
//! );
//!
//! assert_eq!(2, MyEnum::Two.ordinal());
//! assert_eq!(Some(MyEnum::One), MyEnum::from_ordinal(1));
//!
//! create_ordinalized_enum!(pub MyPublicEnum,
//!     u8,
//!     A,
//!     B,
//!     C
//! );
//!
//! assert_eq!(2, MyPublicEnum::C.ordinal());
//! assert_eq!(Some(MyPublicEnum::B), MyPublicEnum::from_ordinal(1));
//!
//! create_ordinalized_enum!(MySpecialEnum,
//!     u8,
//!     Two = 2,
//!     Four = 4,
//!     Eight = 8
//! );
//!
//! assert_eq!(2, MySpecialEnum::Two.ordinal());
//! assert_eq!(Some(MySpecialEnum::Four), MySpecialEnum::from_ordinal(4));
//! ```

/// Implement a `ordinal` method and a `from_ordinal` associated function for an existing `enum`.
#[macro_export]
macro_rules! ordinalize_enum {
    ( $name:ident, $t:ty $( , $variants:ident )+ $(,)* ) => {
        impl $name {
            fn ordinal(&self) -> $t {
                match self {
                    $(
                        $name::$variants => $name::$variants as $t,
                    )+
                }
            }

            fn from_ordinal(number: $t) -> Option<$name> {
                match number{
                    $(
                        n if n == ($name::$variants as $t) => Some($name::$variants),
                    )+
                    _ => None
                }
            }
        }
    }
}

/// Create an enum and implement a `ordinal` method and a `from_ordinal` associated function for it. The new enum also implements `Debug`, `PartialEq`, and `Clone` traits.
#[macro_export]
macro_rules! create_ordinalized_enum {
    ( $name:ident, $t:ty $( ,$variants:ident )+ $(,)* ) => {
        #[derive(Debug, PartialEq, Clone)]
        enum $name {
            $(
                $variants,
            )+
        }
        ordinalize_enum!(
            $name,
            $t,
            $(
                $variants,
            )+
        );
    };
    ( $name:ident, $t:ty $( ,$variants:ident = $values:expr )+ $(,)* ) => {
        #[derive(Debug, PartialEq, Clone)]
        enum $name {
            $(
                $variants = $values,
            )+
        }
        ordinalize_enum!(
            $name,
            $t,
            $(
                $variants,
            )+
        );
    };
    ( pub $name:ident, $t:ty $( ,$variants:ident )+ $(,)* ) => {
        #[derive(Debug, PartialEq, Clone)]
        pub enum $name {
            $(
                $variants,
            )+
        }
        ordinalize_enum!(
            $name,
            $t,
            $(
                $variants,
            )+
        );
    };
    ( pub $name:ident, $t:ty $( ,$variants:ident = $values:expr )+ $(,)* ) => {
        #[derive(Debug, PartialEq, Clone)]
        pub enum $name {
            $(
                $variants = $values,
            )+
        }
        ordinalize_enum!(
            $name,
            $t,
            $(
                $variants,
            )+
        );
    };
}