#![doc(hidden)] /// Creates an enumeration and function for converting a representation into the /// enumeration type. /// /// The syntax is similar to the `c_bitfield` macro, but each value has the /// syntax `value = enumeration`. `enum` is used instead of `struct`. /// /// This will generate an `enum $t` as well as implement `TryFrom` on it which /// will return `Result<$t, ReprError>`. /// /// # Examples /// /// ``` /// use maraiah::{c_enum, err::ReprError}; /// use std::convert::TryFrom; /// /// c_enum! { /// enum MyEnum: u16 { /// Zero = 0, /// One = 1, /// Two = 2 /// } /// } /// /// assert_eq!(MyEnum::try_from(0), Ok(MyEnum::Zero)); /// assert_eq!(MyEnum::try_from(1), Ok(MyEnum::One)); /// assert_eq!(MyEnum::try_from(2), Ok(MyEnum::Two)); /// assert_eq!(MyEnum::try_from(3), Err(ReprError::new("MyEnum", 3))); /// assert_eq!(MyEnum::try_from(4), Err(ReprError::new("MyEnum", 4))); /// assert_eq!(MyEnum::try_from(5), Err(ReprError::new("MyEnum", 5))); /// ``` #[macro_export] macro_rules! c_enum { ( $(#[$outer:meta])* $vi:vis enum $t:ident: $ti:ident { $( $(#[$inner:meta])* $en:ident = $va:expr ),+ $(,)? } ) => { $(#[$outer])* #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] #[repr($ti)] $vi enum $t { $( $(#[$inner])* $en = $va, )+ } #[allow(unused_qualifications)] impl std::convert::TryFrom<$ti> for $t { type Error = $crate::err::ReprError; /// Returns, if representable, the variant of `Self` from `n`. fn try_from(n: $ti) -> Result { match n { $($va => Ok($t::$en),)+ n => Err(Self::Error::new(stringify!($t), n)) } } } #[allow(unused_qualifications)] impl std::str::FromStr for $t { type Err = $crate::err::ParseEnumError; fn from_str(s: &str) -> Result { match s { $( stringify!($en) => Ok($t::$en), )+ _ => Err(Self::Err::new(stringify!($t))) } } } }; } #[cfg(test)] mod test { use crate::err::{ParseEnumError, ReprError}; use std::{convert::TryFrom, str::FromStr}; c_enum! { enum TestEnum: u16 { Zero = 0, One = 1, Two = 2, } } #[test] fn c_enum() { assert_eq!(TestEnum::try_from(0), Ok(TestEnum::Zero)); assert_eq!(TestEnum::try_from(1), Ok(TestEnum::One)); assert_eq!(TestEnum::try_from(2), Ok(TestEnum::Two)); assert_eq!(TestEnum::try_from(3), Err(ReprError::new("TestEnum", 3))); assert_eq!(TestEnum::try_from(4), Err(ReprError::new("TestEnum", 4))); assert_eq!(TestEnum::try_from(5), Err(ReprError::new("TestEnum", 5))); assert_eq!(TestEnum::from_str("Zero"), Ok(TestEnum::Zero)); assert_eq!(TestEnum::from_str("One"), Ok(TestEnum::One)); assert_eq!(TestEnum::from_str("Two"), Ok(TestEnum::Two)); assert_eq!(TestEnum::from_str("Three"), Err(ParseEnumError::new("TestEnum"))); } } // EOF