value_enum/
lib.rs

1//! Macro for generating enums associated with values.
2//! 
3//! # Example
4//! 
5//! ```
6//! use value_enum::value_enum;
7//! 
8//! value_enum!(
9//!     #[derive(Clone, Copy, PartialEq, Eq, Debug)]
10//!     enum Abc: char {
11//!         A = 'a',
12//!         B = 'b',
13//!         C = 'c',
14//!     }
15//! );
16//! 
17//! assert_eq!(char::from(Abc::A), 'a');
18//! assert_eq!(Abc::try_from('b'), Ok(Abc::B));
19//! ```
20
21/// Macro for generating enums associated with values.
22/// 
23/// # Example
24/// 
25/// ```
26/// use value_enum::value_enum;
27/// 
28/// value_enum!(
29///     #[derive(Clone, Copy, PartialEq, Eq, Debug)]
30///     enum Abc: char {
31///         A = 'a',
32///         B = 'b',
33///         C = 'c',
34///     }
35/// );
36/// 
37/// assert_eq!(char::from(Abc::A), 'a');
38/// assert_eq!(Abc::try_from('b'), Ok(Abc::B));
39/// ```
40#[macro_export]
41macro_rules! value_enum {
42    (
43        $(#[$attr:meta])*
44        $vis:vis enum $name:ident: $type:ty {
45            $($variant:ident = $value:expr),*
46            $(,)?
47        }
48    ) => {
49        $(#[$attr])*
50        $vis enum $name {
51            $($variant,)*
52        }
53
54        impl From<$name> for $type {
55            fn from(val: $name) -> Self {
56                match val {
57                    $($name::$variant => $value,)*
58                }
59            }
60        }
61
62        impl TryFrom<$type> for $name {
63            type Error = $type;
64
65            #[allow(non_upper_case_globals)]
66            fn try_from(val: $type) -> Result<Self, Self::Error> {
67                $(
68                    const $variant: $type = $value;
69                )*
70                match val {
71                    $($variant => Ok($name::$variant),)*
72                    _ => Err(val),
73                }
74            }
75        }
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    value_enum!(
84        #[derive(Clone, Copy, PartialEq, Eq, Debug)]
85        enum Abc: char {
86            A = 'a',
87            B = 'b',
88            C = 'c',
89        }
90    );
91
92    value_enum!(
93        #[derive(Clone, Copy, PartialEq, Eq, Debug)]
94        enum Str: (&'static str, &'static str) {
95            Test = ("test", "qwerty"),
96            Nya = ("nya", "nyan"),
97        }
98    );
99
100    #[test]
101    fn test_char() {
102        assert_eq!(char::from(Abc::A), 'a');
103        assert_eq!(Abc::try_from('a'), Ok(Abc::A));
104        assert_eq!(char::from(Abc::B), 'b');
105        assert_eq!(Abc::try_from('b'), Ok(Abc::B));
106        assert_eq!(char::from(Abc::C), 'c');
107        assert_eq!(Abc::try_from('c'), Ok(Abc::C));
108        assert_eq!(Abc::try_from('d'), Err('d'));
109    }
110
111    #[test]
112    fn test_str() {
113        assert_eq!(<(&str, &str)>::from(Str::Test), ("test", "qwerty"));
114        assert_eq!(Str::try_from(("test", "qwerty")), Ok(Str::Test));
115        assert_eq!(<(&str, &str)>::from(Str::Nya), ("nya", "nyan"));
116        assert_eq!(Str::try_from(("nya", "nyan")), Ok(Str::Nya));
117        assert_eq!(Str::try_from(("wtf", "wtf")), Err(("wtf", "wtf")));
118    }
119}