Maraiah/maraiah/cbitfield.rs

89 lines
2.0 KiB
Rust

#![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<Self, Self::Err>
{
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