bitflag_attr_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::ToTokens;
3use syn::{Error, Result};
4use typed::{Args, Bitflag};
5
6mod typed;
7
8/// An attribute macro that transforms an C-like enum into a bitflag struct type implementing an API
9/// similar to the `bitflags` crate, and implementing many helpful traits (listed in more details
10/// below).
11///
12/// The attribute requires that the [`Clone`] and [`Copy`] traits are derived for the type.
13///
14/// [`Clone`]: ::core::clone::Clone
15/// [`Copy`]: ::core::marker::Copy
16///
17/// ## Examples
18///
19/// Generate a flags type using `u8` as the bits type:
20/// ```rust
21/// # use bitflag::bitflag;
22///
23/// #[bitflag(u8)]
24/// #[derive(Clone, Copy)]
25/// enum Flags {
26///     A = 1,
27///     B = 1 << 1,
28///     C = 0b0000_0100,
29/// }
30/// ```
31///
32/// Flags may refer to other flags using their names:
33///
34/// ```rust
35/// # use bitflag::bitflag;
36///
37/// #[bitflag(u8)]
38/// #[derive(Clone, Copy)]
39/// enum Flags {
40///     A = 1,
41///     B = 1 << 1,
42///     C = 0b0000_0100,
43///     AB = A | B,
44/// }
45/// ```
46///
47/// Flags may also refer to other flags using their `bits` method value, like `bitflags` crate:
48///
49/// ```rust
50/// # use bitflag::bitflag;
51///
52/// #[bitflag(u8)]
53/// #[derive(Clone, Copy)]
54/// enum Flags {
55///     A = 1,
56///     B = 1 << 1,
57///     C = 0b0000_0100,
58///     AB = Flags::A.bits() | Flags::B.bits(),
59/// }
60/// ```
61///
62/// It's possible to use more derives and attributes by simply adding them
63///
64/// ```rust
65/// # use core::fmt::Debug as ExternalDerive
66///
67/// #[bitflag(u8)]
68/// #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, ExternalDerive)]
69/// enum Flags {
70///     A = 1,
71///     B = 1 << 1,
72///     C = 0b0000_0100,
73///     AB = Flags::A.bits() | Flags::B.bits(),
74/// }
75/// ```
76///
77/// ## Known and unknown flags
78///
79/// The variant of the enum are flags. They will be expanded to type-associated constants. Every
80/// variant value is a known flag, while every not specified value is a unknown flag.
81///
82/// There are operation that will truncate out the unknown values. But tha can be configured if
83/// desired; more on that on [Externally defined flags](#externally-defined-flags)
84///
85/// ## Externally defined flags
86///
87/// If you're generating flags types for an external source, such as a C API, you can use the
88/// `non_exhaustive` attribute to communicate to the bitflags macro that there may be more valid
89/// flags then the known flags.
90///
91/// Without extra configuration, it defaults to `!0` (all bits set) as a mask of all bits the
92/// external source may ever set, i.e. all bits are considered as possible values.
93///
94/// ```
95/// use bitflag::bitflag;
96///
97/// #[bitflag(u32)]
98/// #[non_exhaustive] // All bits are considered as possible values.
99/// #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
100/// pub enum Flags {
101///     /// The value `A`, at bit position `0`.
102///     A = 0b00000001,
103///     /// The value `B`, at bit position `1`.
104///     B = 0b00000010,
105///     /// The value `C`, at bit position `2`.
106///     C = 0b00000100,
107///
108///     /// The combination of `A`, `B`, and `C`.
109///     ABC = A | B | C,
110/// }
111/// ```
112///
113/// But you can also configure it using the helper attribute `extra_valid_bits` with the value of
114/// valid bits that the external source may ever set.
115///
116/// ```
117/// use bitflag::bitflag;
118///
119/// #[bitflag(u32)]
120/// #[non_exhaustive] // Communicate there is more potential valid flags than the known flags
121/// #[extra_valid_bits = 0b001001111] // Specify the extra bits to take into consideration.
122/// #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
123/// pub enum Flags {
124///     /// The value `A`, at bit position `0`.
125///     A = 0b00000001,
126///     /// The value `B`, at bit position `1`.
127///     B = 0b00000010,
128///     /// The value `C`, at bit position `2`.
129///     C = 0b00000100,
130///
131///     /// The combination of `A`, `B`, and `C`.
132///     ABC = A | B | C,
133/// }
134/// ```
135///
136/// Why should you do this? Generated methods like `all` and truncating operators like `!` only
137/// consider bits in defined flags. Adding an unnamed flag makes those methods consider additional
138/// bits, without generating additional constants for them. It helps compatibility when the external
139/// source may start setting additional bits at any time.
140///
141/// ## Type representation
142///
143/// By default, the generated flag type will be `#[repr(transparent)]`, but you can explicit it on
144/// the definition as long is one of the supported ones (`C`, `Rust` and `transparent`):
145///
146/// ```rust
147/// # use bitflag::bitflag;
148///
149/// #[repr(C)]
150/// #[bitflag(u8)]
151/// #[derive(Clone, Copy)]
152/// enum Flags {
153///     A = 1,
154///     B = 1 << 1,
155///     C = 1 << 2,
156/// }
157/// ```
158///
159/// ## Generated trait implementations
160///
161/// This macro generates some trait implementations: [`ops:Not`], [`ops:BitAnd`],
162/// [`ops:BitOr`], [`ops:BitXor`], [`ops:BitAndAssign`], [`ops:BitOrAssign`], [`ops:BitXorAssign`],
163/// [`fmt::Binary`], [`fmt::LowerHex`], [`fmt::UpperHex`], [`fmt::Octal`], [`From`], [`Extend`],
164/// [`FromIterator`], [`FromStr`] and [`IntoIterator`].
165///
166/// The custom [`fmt::Debug`] implementation will only be generated if it is included in the
167/// `#[derive(...)]` parameters.
168///
169/// The custom [`Default`] implementation will only be generated if it is included in the
170/// `#[derive(...)]` parameters.
171///
172/// [`IntoIterator`]: core::iter::IntoIterator
173/// [`Default`]: core::default::Default
174///
175/// ### Default derive
176///
177/// The `bitflag` macro handles the [`Default`] if specified in the derive list. Without specifying
178/// a default variant, the default implementation is the same as a empty flag:
179///
180/// ```rust
181/// # use bitflag::bitflag;
182///
183/// #[bitflag(u8)]
184/// #[derive(Clone, Copy, Default)] // Default is the same as `Flags::empty()`
185/// enum Flags {
186///     A = 1,
187///     B = 1 << 1,
188///     C = 1 << 2,
189/// }
190/// ```
191///
192/// But it can be specified like deriving [`Default`] on enum, using the `#[default]` helper attribute:
193///
194/// ```rust
195/// # use bitflag::bitflag;
196///
197/// #[bitflag(u8)]
198/// #[derive(Clone, Copy, Default)]
199/// enum Flags {
200///     A = 1,
201///     B = 1 << 1,
202///     #[default] // `Flags::C` are the default value returned by `Default::default()`
203///     C = 1 << 2,
204/// }
205/// ```
206///
207/// ### Serde feature
208///
209/// If the crate is compiled with the `serde` feature, this crate will generate implementations for
210/// the `serde::{Serialize, Deserialize}` traits if they are included in the `#[derive(...)]`
211/// parameters, but it will not import/re-export these traits, your project must have `serde` as
212/// a direct dependency.
213///
214/// ```no_run
215/// use bitflag::bitflag;
216/// use serde::{Serialize, Deserialize};
217///
218/// #[bitflag(u32)]
219/// #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
220/// pub enum Flags {
221///     /// The value `A`, at bit position `0`.
222///     A = 0b00000001,
223///     /// The value `B`, at bit position `1`.
224///     B = 0b00000010,
225///     /// The value `C`, at bit position `2`.
226///     C = 0b00000100,
227///
228///     /// The combination of `A`, `B`, and `C`.
229///     ABC = A | B | C,
230/// }
231/// ```
232///
233/// ### Arbitrary feature
234///
235/// If the crate is compiled with the `arbitrary` feature, this crate will generate implementations for
236/// the `arbitrary::Arbitrary` traits if they are included in the `#[derive(...)]`
237/// parameters, but it will not import/re-export these traits, your project must have `arbitrary` as
238/// a direct dependency.
239///
240/// ```no_run
241/// use bitflag::bitflag;
242/// use arbitrary::Arbitrary;
243///
244/// #[bitflag(u32)]
245/// #[derive(Clone, Copy, Arbitrary)]
246/// enum Color {
247///     RED = 0x1,
248///     GREEN = 0x02,
249///     BLUE = 0x4,
250/// }
251/// ```
252///
253/// ### Bytemuck feature
254///
255/// If the crate is compiled with the `bytemuck` feature, this crate will generate implementations for
256/// the `bytemuck::{Pod, Zeroable}` traits if they are included in the `#[derive(...)]`
257/// parameters, but it will not import/re-export these traits, your project must have `bytemuck` as
258/// a direct dependency.
259///
260/// ```no_run
261/// use bitflag::bitflag;
262/// use bytemuck::{Pod, Zeroable};
263///
264/// #[bitflag(u32)]
265/// #[derive(Debug, Clone, Copy, Pod, Zeroable)]
266/// pub enum Flags {
267///     /// The value `A`, at bit position `0`.
268///     A = 0b00000001,
269///     /// The value `B`, at bit position `1`.
270///     B = 0b00000010,
271///     /// The value `C`, at bit position `2`.
272///     C = 0b00000100,
273///
274///     /// The combination of `A`, `B`, and `C`.
275///     ABC = A | B | C,
276/// }
277/// ```
278///
279/// ### `const-mut-ref` feature
280///
281/// If the crate is compiled with the `const-mut-ref` feature, all type-associated API that takes
282/// `&mut self` will be generated as **const-fn**, meaning they can be used on `const` context.
283///
284/// **Note:** `&mut` on const function was stabilized on Rust 1.83.0, so using this feature flag on
285/// Rust versions below that will cause compilation errors
286///
287/// ### Custom types feature
288///
289/// If the crate is compiled with the `custom-types` feature, it allows to use more than the types
290/// defined in Rust `core` (`i8`,`u8`,`i16`,`u16`,`i32`,`u32`,`i64`,`u64`,`i128`,`u128`,`isize`,
291/// `usize`,`c_char`,`c_schar`,`c_uchar`,`c_short`,`c_ushort`,`c_int`,`c_uint`,`c_long`,`c_ulong`,
292/// `c_longlong`,`c_ulonglong`) as long as it is a type alias to one of those types.
293///
294/// The reason it is behind a feature flag is that to ensure the validity of such constrain, we have
295/// to pay the price of having much worse error messages. With this feature enabled, a invalid type
296/// will cause a massive wall of error message.
297///
298///
299/// # More Examples
300///
301/// ```
302/// use bitflag::bitflag;
303///
304/// #[bitflag(u32)]
305/// #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
306/// pub enum Flags {
307///     /// The value `A`, at bit position `0`.
308///     A = 0b00000001,
309///     /// The value `B`, at bit position `1`.
310///     B = 0b00000010,
311///     /// The value `C`, at bit position `2`.
312///     C = 0b00000100,
313///
314///     /// The combination of `A`, `B`, and `C`.
315///     ABC = A | B | C,
316/// }
317/// ```
318///
319/// Without generating [`fmt::Debug`]:
320///
321/// ```
322/// use bitflag::bitflag;
323///
324/// #[bitflag(u32)]
325/// #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
326/// pub enum Flags {
327///     /// The value `A`, at bit position `0`.
328///     A = 0b00000001,
329///     /// The value `B`, at bit position `1`.
330///     B = 0b00000010,
331///     /// The value `C`, at bit position `2`.
332///     C = 0b00000100,
333///
334///     /// The combination of `A`, `B`, and `C`.
335///     ABC = A | B | C,
336/// }
337/// ```
338///
339/// # Syntax
340///
341/// ```text
342/// #[bitflag($ty)]
343/// $visibility enum $StructName {
344///     FlagOne = flag1_value_expr,
345///     FlagTwo = flag2_value_expr,
346///     // ...
347///     FlagN = flagn_value_expr,
348/// }
349/// ```
350///
351/// [`fmt::Debug`]: core::fmt::Debug
352/// [`ops:Not`]: core::ops::Not
353/// [`ops:BitAnd`]: core::ops::BitAnd
354/// [`ops:BitOr`]: core::ops::BitOr
355/// [`ops:BitXor`]: core::ops::BitXor
356/// [`ops:BitAndAssign`]: core::ops::BitAndAssign
357/// [`ops:BitOrAssign`]: core::ops::BitOrAssign
358/// [`ops:BitXorAssign`]: core::ops::BitXorAssign
359/// [`fmt::Binary`]: core::fmt::Binary
360/// [`fmt::LowerHex`]: core::fmt::LowerHex
361/// [`fmt::UpperHex`]: core::fmt::UpperHex
362/// [`fmt::Octal`]: core::fmt::Octal
363/// [`From`]: From
364/// [`FromStr`]: core::str::FromStr
365#[proc_macro_attribute]
366pub fn bitflag(attr: TokenStream, item: TokenStream) -> TokenStream {
367    match bitflag_impl(attr, item) {
368        Ok(ts) => ts,
369        Err(err) => err.into_compile_error().into(),
370    }
371}
372
373fn bitflag_impl(attr: TokenStream, item: TokenStream) -> Result<TokenStream> {
374    let args: Args = syn::parse(attr)
375        .map_err(|err| Error::new(err.span(), "unexpected token: expected a `{integer}` type"))?;
376
377    let bitflag = Bitflag::parse(args, item)?;
378
379    Ok(bitflag.to_token_stream().into())
380}