diff --git a/README.md b/README.md index 8755d01..6e8f9a6 100644 --- a/README.md +++ b/README.md @@ -26,16 +26,17 @@ extern crate bitflags; extern crate bitflags_derive; bitflags! { - #[derive(FlagsDebug)] - struct Flags: u8 { + #[derive(FlagsDisplay, FlagsFromStr)] + struct MyFlags: u8 { const A = 1; const B = 1 << 1; const C = 1 << 2; } } -// The regular `#[derive(Debug)]` would produce "Flags(A | B)" here -assert_eq!("A | B", format!("{:?}", Flags::A | Flags::B)); +let flags = "A | B".parse::()?; + +assert_eq!("A | B", flags.to_string()); ``` See [the docs](https://docs.rs/bitflags-derive) for details on all supported attributes. diff --git a/macros/src/display.rs b/macros/src/display.rs new file mode 100644 index 0000000..d0c61f2 --- /dev/null +++ b/macros/src/display.rs @@ -0,0 +1,14 @@ +use proc_macro2::TokenStream; + +pub(crate) fn expand(item: syn::DeriveInput) -> Result { + let ident = item.ident; + let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl(); + + Ok( + quote!(impl #impl_generics bitflags_derive::__private::core::fmt::Display for #ident #ty_generics #where_clause { + fn fmt(&self, f: &mut bitflags_derive::__private::core::fmt::Formatter) -> bitflags_derive::__private::core::fmt::Result { + bitflags_derive::__private::bitflags::parser::to_writer(self, f) + } + }), + ) +} diff --git a/macros/src/from_str.rs b/macros/src/from_str.rs new file mode 100644 index 0000000..3b97118 --- /dev/null +++ b/macros/src/from_str.rs @@ -0,0 +1,16 @@ +use proc_macro2::TokenStream; + +pub(crate) fn expand(item: syn::DeriveInput) -> Result { + let ident = item.ident; + let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl(); + + Ok( + quote!(impl #impl_generics bitflags_derive::__private::core::str::FromStr for #ident #ty_generics #where_clause { + type Err = bitflags_derive::__private::bitflags::parser::ParseError; + + fn from_str(v: &str) -> bitflags_derive::__private::core::result::Result { + bitflags_derive::__private::bitflags::parser::from_str(v) + } + }), + ) +} diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 6840379..b4a1389 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -12,9 +12,11 @@ extern crate proc_macro; extern crate quote; mod debug; +mod display; +mod from_str; /** -Derive [`Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html) for a flags type. +Derive [`Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html). This macro will use [`to_writer`](https://docs.rs/bitflags/latest/bitflags/parser/fn.to_writer.html) to format flags values. @@ -24,6 +26,28 @@ pub fn derive_bitflags_debug(item: proc_macro::TokenStream) -> proc_macro::Token debug::expand(syn::parse_macro_input!(item as syn::DeriveInput)).unwrap_or_compile_error() } +/** +Derive [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html). + +This macro will use [`to_writer`](https://docs.rs/bitflags/latest/bitflags/parser/fn.to_writer.html) to +format flags values. +*/ +#[proc_macro_derive(FlagsDisplay)] +pub fn derive_bitflags_display(item: proc_macro::TokenStream) -> proc_macro::TokenStream { + display::expand(syn::parse_macro_input!(item as syn::DeriveInput)).unwrap_or_compile_error() +} + +/** +Derive [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html). + +This macro will use [`from_str`](https://docs.rs/bitflags/latest/bitflags/parser/fn.from_str.html) to +parse flags values. +*/ +#[proc_macro_derive(FlagsFromStr)] +pub fn derive_bitflags_from_str(item: proc_macro::TokenStream) -> proc_macro::TokenStream { + from_str::expand(syn::parse_macro_input!(item as syn::DeriveInput)).unwrap_or_compile_error() +} + trait ResultExt { fn unwrap_or_compile_error(self) -> proc_macro::TokenStream; } diff --git a/src/lib.rs b/src/lib.rs index 4fa9786..dac9859 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,18 +22,27 @@ extern crate bitflags; #[macro_use] extern crate bitflags_derive; +# fn main() -> Result<(), bitflags::parser::ParseError> { bitflags! { - #[derive(FlagsDebug)] - struct Flags: u8 { + #[derive(FlagsDisplay, FlagsFromStr)] + struct MyFlags: u8 { const A = 1; const B = 1 << 1; const C = 1 << 2; } } -# fn main() {} + +let flags = "A | B".parse::()?; + +assert_eq!("A | B", flags.to_string()); +# Ok(()) +# } ``` + +These derives work for any type that implements the [`Flags`](https://docs.rs/bitflags/latest/bitflags/trait.Flags.html) trait. */ +#![no_std] #![deny(missing_docs)] #[doc(inline)] diff --git a/tests/ui/src/display.rs b/tests/ui/src/display.rs new file mode 100644 index 0000000..7c58010 --- /dev/null +++ b/tests/ui/src/display.rs @@ -0,0 +1,13 @@ +#[test] +fn derive_display() { + bitflags! { + #[derive(FlagsDisplay)] + struct Flags: u8 { + const A = 1; + const B = 1 << 1; + const C = 1 << 2; + } + } + + assert_eq!("A | B", (Flags::A | Flags::B).to_string()); +} diff --git a/tests/ui/src/from_str.rs b/tests/ui/src/from_str.rs new file mode 100644 index 0000000..89de93c --- /dev/null +++ b/tests/ui/src/from_str.rs @@ -0,0 +1,13 @@ +#[test] +fn derive_from_str() { + bitflags! { + #[derive(FlagsFromStr, PartialEq, Eq, Debug)] + struct Flags: u8 { + const A = 1; + const B = 1 << 1; + const C = 1 << 2; + } + } + + assert_eq!("A | B".parse::().unwrap(), Flags::A | Flags::B); +} diff --git a/tests/ui/src/lib.rs b/tests/ui/src/lib.rs index a383c39..78dce11 100644 --- a/tests/ui/src/lib.rs +++ b/tests/ui/src/lib.rs @@ -7,3 +7,5 @@ extern crate bitflags; extern crate bitflags_derive; mod debug; +mod display; +mod from_str;