Skip to content

Commit d09a8cf

Browse files
committed
Allow customizing defaults
1 parent ebffedd commit d09a8cf

File tree

3 files changed

+88
-15
lines changed

3 files changed

+88
-15
lines changed

README.md

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@
55

66
# Enumflags
77

8-
`enumflags2` defines a `BitFlags<T>` type, which is a `Set<T>`
9-
for enums without associated data.
10-
11-
This means that the type of a single flag is separate from a set of flags.
8+
`enumflags2` implements the classic bitflags datastructure. Annotate an enum
9+
with `#[bitflags]`, and `BitFlags<YourEnum>` will be able to hold arbitrary combinations
10+
of your enum within the space of a single integer.
1211

1312
## Usage
1413

@@ -28,7 +27,8 @@ enumflags2 = "^0.6"
2827
- [x] Optional support for serialization with the [`serde`](https://serde.rs/) feature flag.
2928

3029
## Example
31-
```
30+
31+
```rust
3232
use enumflags2::{bitflags, make_bitflags, BitFlags};
3333

3434
#[bitflags]
@@ -91,4 +91,23 @@ want to write a separate implementation for `BitFlags<T, u8>`,
9191
This strategy is often used by `enumflags2` itself; to avoid clutter, only
9292
one of the copies is shown in the documentation.
9393

94+
## Customizing `Default`
95+
96+
By default, creating an instance of `BitFlags<T>` with `Default` will result in an empty
97+
set. If that's undesirable, you may customize this:
98+
99+
```rust
100+
#[bitflags(default = B | C)]
101+
#[repr(u8)]
102+
#[derive(Copy, Clone, Debug, PartialEq)]
103+
enum Test {
104+
A = 0b0001,
105+
B = 0b0010,
106+
C = 0b0100,
107+
D = 0b1000,
108+
}
109+
110+
assert_eq!(BitFlags::default(), Test::B | Test::C);
111+
```
112+
94113
[const-trait-rfc]: https://github.com/rust-lang/rfcs/pull/2632

enumflags_derive/src/lib.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ extern crate proc_macro;
44
extern crate quote;
55

66
use std::convert::TryFrom;
7-
use syn::{Ident, Item, ItemEnum, spanned::Spanned, parse_macro_input};
7+
use syn::{Token, Ident, Item, ItemEnum, spanned::Spanned, parse_macro_input, parse::{Parse, ParseStream}};
88
use proc_macro2::{TokenStream, Span};
99

1010
struct Flag {
@@ -19,14 +19,41 @@ enum FlagValue {
1919
Inferred,
2020
}
2121

22+
struct Parameters {
23+
default: Vec<Ident>,
24+
}
25+
26+
impl Parse for Parameters {
27+
fn parse(input: ParseStream) -> syn::parse::Result<Self> {
28+
if input.is_empty() {
29+
return Ok(Parameters {
30+
default: vec![],
31+
});
32+
}
33+
34+
input.parse::<Token![default]>()?;
35+
input.parse::<Token![=]>()?;
36+
let mut default = vec![input.parse()?];
37+
while !input.is_empty() {
38+
input.parse::<Token![|]>()?;
39+
default.push(input.parse()?);
40+
}
41+
42+
Ok(Parameters {
43+
default
44+
})
45+
}
46+
}
47+
2248
#[proc_macro_attribute]
2349
pub fn bitflags_internal(
24-
_attr: proc_macro::TokenStream,
50+
attr: proc_macro::TokenStream,
2551
input: proc_macro::TokenStream,
2652
) -> proc_macro::TokenStream {
53+
let Parameters { default } = parse_macro_input!(attr as Parameters);
2754
let ast = parse_macro_input!(input as Item);
2855
let output = match ast {
29-
Item::Enum(ref item_enum) => gen_enumflags(item_enum),
56+
Item::Enum(ref item_enum) => gen_enumflags(item_enum, default),
3057
_ => Err(syn::Error::new_spanned(&ast,
3158
"#[bitflags] requires an enum")),
3259
};
@@ -190,7 +217,7 @@ fn check_flag(
190217
}
191218
}
192219

193-
fn gen_enumflags(ast: &ItemEnum)
220+
fn gen_enumflags(ast: &ItemEnum, default: Vec<Ident>)
194221
-> Result<TokenStream, syn::Error>
195222
{
196223
let ident = &ast.ident;
@@ -264,6 +291,9 @@ fn gen_enumflags(ast: &ItemEnum)
264291

265292
const EMPTY: Self::Numeric = 0;
266293

294+
const DEFAULT: Self::Numeric =
295+
0 #(| (#repeated_name::#default as #ty))*;
296+
267297
const ALL_BITS: Self::Numeric =
268298
0 #(| (#repeated_name::#variant_names as #ty))*;
269299

src/lib.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
//! # Enum Flags
2-
//! `enumflags2` defines a `BitFlags<T>` type, which is a `Set<T>`
3-
//! for enums without associated data.
4-
//!
5-
//! This means that the type of a single flag is separate from a set of flags.
2+
//! `enumflags2` implements the classic bitflags datastructure. Annotate an enum
3+
//! with `#[bitflags]`, and `BitFlags<YourEnum>` will be able to hold arbitrary combinations
4+
//! of your enum within the space of a single integer.
65
//!
76
//! ## Example
87
//! ```
@@ -68,6 +67,26 @@
6867
//! This strategy is often used by `enumflags2` itself; to avoid clutter, only
6968
//! one of the copies is shown in the documentation.
7069
//!
70+
//! ## Customizing `Default`
71+
//!
72+
//! By default, creating an instance of `BitFlags<T>` with `Default` will result in an empty
73+
//! set. If that's undesirable, you may customize this:
74+
//!
75+
//! ```
76+
//! # use enumflags2::{BitFlags, bitflags};
77+
//! #[bitflags(default = B | C)]
78+
//! #[repr(u8)]
79+
//! #[derive(Copy, Clone, Debug, PartialEq)]
80+
//! enum Test {
81+
//! A = 0b0001,
82+
//! B = 0b0010,
83+
//! C = 0b0100,
84+
//! D = 0b1000,
85+
//! }
86+
//!
87+
//! assert_eq!(BitFlags::default(), Test::B | Test::C);
88+
//! ```
89+
//!
7190
//! [const-trait-rfc]: https://github.com/rust-lang/rfcs/pull/2632
7291
#![warn(missing_docs)]
7392
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
@@ -174,6 +193,10 @@ pub mod _internal {
174193
/// A value with no bits set.
175194
const EMPTY: Self::Numeric;
176195

196+
/// The value used by the Default implementation. Equivalent to EMPTY, unless
197+
/// customized.
198+
const DEFAULT: Self::Numeric;
199+
177200
/// A value with all flag bits set.
178201
const ALL_BITS: Self::Numeric;
179202

@@ -357,14 +380,15 @@ macro_rules! make_bitflags {
357380
}
358381
}
359382

360-
/// The default value returned is one with all flags unset, i. e. [`empty`][Self::empty].
383+
/// The default value returned is one with all flags unset, i. e. [`empty`][Self::empty],
384+
/// unless customized.
361385
impl<T> Default for BitFlags<T>
362386
where
363387
T: BitFlag,
364388
{
365389
#[inline(always)]
366390
fn default() -> Self {
367-
Self::empty()
391+
BitFlags { val: T::DEFAULT, marker: PhantomData }
368392
}
369393
}
370394

0 commit comments

Comments
 (0)