1#[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}