#![doc(hidden)] /// A wrapper for `bitflags!` which adds a `FromStr` implementation. #[macro_export] macro_rules! c_bitfield { ( $(#[$outer:meta])* pub struct $t:ident: $ti:ty { $( $(#[$inner:ident $($args:tt)*])* $f:ident = $v:expr ),+ $(,)? } ) => { bitflags! { $(#[$outer])* pub struct $t: $ti { $( $(#[$inner $($args)*])* const $f = 1 << $v; )+ } } #[allow(unused_qualifications)] impl std::str::FromStr for $t { type Err = $crate::err::ParseFlagError; fn from_str(s: &str) -> Result { let mut flags = Self::empty(); for s in s.split('|') { match s { $( stringify!($f) => flags.insert(Self::$f), )+ "(none)" => (), _ => return Err(Self::Err::new(stringify!($t))) } } Ok(flags) } } } } #[cfg(test)] mod test { use crate::err::ParseFlagError; use std::str::FromStr; c_bitfield! { pub struct TestFlag: u16 { ZERO = 0, ONE = 1, TWO = 2, } } #[test] fn c_bitfield() { assert_eq!(TestFlag::from_bits(0), Some(TestFlag::empty())); assert_eq!(TestFlag::from_bits(1), Some(TestFlag::ZERO)); assert_eq!(TestFlag::from_bits(2), Some(TestFlag::ONE)); assert_eq!(TestFlag::from_bits(4), Some(TestFlag::TWO)); assert_eq!(TestFlag::from_bits(8), None); assert_eq!(TestFlag::from_str("(none)"), Ok(TestFlag::empty())); assert_eq!(TestFlag::from_str("ZERO"), Ok(TestFlag::ZERO)); assert_eq!(TestFlag::from_str("ONE"), Ok(TestFlag::ONE)); assert_eq!(TestFlag::from_str("TWO"), Ok(TestFlag::TWO)); assert_eq!(TestFlag::from_str("ZERO|ONE|TWO"), Ok(TestFlag::all())); assert_eq!(TestFlag::from_str("TWO|ZERO|ONE"), Ok(TestFlag::all())); assert_eq!(TestFlag::from_str("ONE|ONE|ONE"), Ok(TestFlag::ONE)); assert_eq!(TestFlag::from_str("(none)|(none)"), Ok(TestFlag::empty())); assert_eq!(TestFlag::from_str("(none)|ONE"), Ok(TestFlag::ONE)); assert_eq!(TestFlag::from_str("THREE"), Err(ParseFlagError::new("TestFlag"))); } } // EOF