bitflags_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
9/// ergonomic end-user API, similar to the `bitflags` crate, and implementing many helpful traits
10/// (listed in more details 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_attr::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_attr::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_attr::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 from 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_attr::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 `reserved_bits` with the value of
114/// valid bits that the external source may ever set.
115///
116/// ```
117/// use bitflag_attr::bitflag;
118///
119/// #[bitflag(u32)]
120/// #[non_exhaustive] // Communicate there is more potential valid flags than the known flags
121/// #[reserved_bits = 0b001001111] // Specify the reserved 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_attr::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/// ### Debug derive
173///
174/// The `bitflag` macro handles the [`fmt::Debug`] if specified in the derive list. When specified,
175/// a customized implementation is produced by the macro where it outputs human-readable, binary,
176/// octal and hexadecimal outputs of the flags value.
177///
178/// ```
179/// # use bitflag_attr::bitflag;
180///
181/// #[bitflag(u32)]
182/// #[derive(Debug, Clone, Copy)]
183/// pub enum Flags {
184///     A = 0b00000001,
185///     B = 0b00000010,
186///     C = 0b00000100,
187/// }
188/// ```
189///
190/// ### Default derive
191///
192/// The `bitflag` macro handles the [`Default`] if specified in the derive list. Without specifying
193/// a default variant, the default implementation is the same as a empty flag:
194///
195/// ```rust
196/// # use bitflag_attr::bitflag;
197///
198/// #[bitflag(u8)]
199/// #[derive(Clone, Copy, Default)] // Default is the same as `Flags::empty()`
200/// enum Flags {
201///     A = 1,
202///     B = 1 << 1,
203///     C = 1 << 2,
204/// }
205/// ```
206///
207/// But it can be specified like deriving [`Default`] on enum, using the `#[default]` helper attribute:
208///
209/// ```rust
210/// # use bitflag_attr::bitflag;
211///
212/// #[bitflag(u8)]
213/// #[derive(Clone, Copy, Default)]
214/// enum Flags {
215///     A = 1,
216///     B = 1 << 1,
217///     #[default] // `Flags::C` are the default value returned by `Default::default()`
218///     C = 1 << 2,
219/// }
220/// ```
221///
222/// ### Serde feature
223///
224/// If the crate is compiled with the `serde` feature, this crate will generate implementations for
225/// the `serde::{Serialize, Deserialize}` traits if they are included in the `#[derive(...)]`
226/// parameters.
227///
228/// ```no_run
229/// use bitflag_attr::bitflag;
230/// use serde::{Serialize, Deserialize};
231///
232/// #[bitflag(u32)]
233/// #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
234/// pub enum Flags {
235///     /// The value `A`, at bit position `0`.
236///     A = 0b00000001,
237///     /// The value `B`, at bit position `1`.
238///     B = 0b00000010,
239///     /// The value `C`, at bit position `2`.
240///     C = 0b00000100,
241///
242///     /// The combination of `A`, `B`, and `C`.
243///     ABC = A | B | C,
244/// }
245/// ```
246///
247/// ### Arbitrary feature
248///
249/// If the crate is compiled with the `arbitrary` feature, this crate will generate implementations for
250/// the `arbitrary::Arbitrary` traits if they are included in the `#[derive(...)]`
251/// parameters, but it will not import/re-export these traits, your project must have `arbitrary` as
252/// a direct dependency.
253///
254/// ```no_run
255/// use bitflag_attr::bitflag;
256/// use arbitrary::Arbitrary;
257///
258/// #[bitflag(u32)]
259/// #[derive(Clone, Copy, Arbitrary)]
260/// enum Color {
261///     RED = 0x1,
262///     GREEN = 0x02,
263///     BLUE = 0x4,
264/// }
265/// ```
266///
267/// ### Bytemuck feature
268///
269/// If the crate is compiled with the `bytemuck` feature, this crate will generate implementations for
270/// the `bytemuck::{Pod, Zeroable}` traits if they are included in the `#[derive(...)]`
271/// parameters, but it will not import/re-export these traits, your project must have `bytemuck` as
272/// a direct dependency.
273///
274/// ```no_run
275/// use bitflag_attr::bitflag;
276/// use bytemuck::{Pod, Zeroable};
277///
278/// #[bitflag(u32)]
279/// #[derive(Debug, Clone, Copy, Pod, Zeroable)]
280/// pub enum Flags {
281///     /// The value `A`, at bit position `0`.
282///     A = 0b00000001,
283///     /// The value `B`, at bit position `1`.
284///     B = 0b00000010,
285///     /// The value `C`, at bit position `2`.
286///     C = 0b00000100,
287///
288///     /// The combination of `A`, `B`, and `C`.
289///     ABC = A | B | C,
290/// }
291/// ```
292///
293/// ### `const-mut-ref` feature
294///
295/// If the crate is compiled with the `const-mut-ref` feature, all type-associated API that takes
296/// `&mut self` will be generated as **const-fn**, meaning they can be used on `const` context.
297///
298/// **Note:** `&mut` on const function was stabilized on Rust 1.83.0, so using this feature flag on
299/// Rust versions below that will cause compilation errors
300///
301/// ### Custom types feature
302///
303/// If the crate is compiled with the `custom-types` feature, it allows to use more than the types
304/// defined in Rust `core` (`i8`,`u8`,`i16`,`u16`,`i32`,`u32`,`i64`,`u64`,`i128`,`u128`,`isize`,
305/// `usize`,`c_char`,`c_schar`,`c_uchar`,`c_short`,`c_ushort`,`c_int`,`c_uint`,`c_long`,`c_ulong`,
306/// `c_longlong`,`c_ulonglong`) and the unix types alias in the `libc` crate as long as it is a type
307/// alias to one of those types.
308///
309/// The reason it is behind a feature flag is that to ensure the validity of such constrain, we have
310/// to pay the price of having much worse error messages. With this feature enabled, a invalid type
311/// will cause a massive wall of error message.
312///
313///
314/// # More Examples
315///
316/// ```
317/// use bitflag_attr::bitflag;
318///
319/// #[bitflag(u32)]
320/// #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
321/// pub enum Flags {
322///     /// The value `A`, at bit position `0`.
323///     A = 0b00000001,
324///     /// The value `B`, at bit position `1`.
325///     B = 0b00000010,
326///     /// The value `C`, at bit position `2`.
327///     C = 0b00000100,
328///
329///     /// The combination of `A`, `B`, and `C`.
330///     ABC = A | B | C,
331/// }
332/// ```
333///
334/// Without generating [`fmt::Debug`]:
335///
336/// ```
337/// use bitflag_attr::bitflag;
338///
339/// #[bitflag(u32)]
340/// #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
341/// pub enum Flags {
342///     /// The value `A`, at bit position `0`.
343///     A = 0b00000001,
344///     /// The value `B`, at bit position `1`.
345///     B = 0b00000010,
346///     /// The value `C`, at bit position `2`.
347///     C = 0b00000100,
348///
349///     /// The combination of `A`, `B`, and `C`.
350///     ABC = A | B | C,
351/// }
352/// ```
353///
354/// # Syntax
355///
356/// ```rust,no_run
357/// #[bitflag($ty)]
358/// #[repr($repr_kind)] // optional: defaults to `repr(transparent)`
359/// #[non_exhaustive] // optional: If set, reserved_bits default to `!0`
360/// #[reserved_bits = $custom_extra_valid_expr] // optional
361/// #[derive(Clone, Copy, $other_derives)]
362/// $visibility enum $StructName {
363///     FlagOne = flag1_value_expr,
364///     FlagTwo = flag2_value_expr,
365///     // ...
366///     FlagN = flagn_value_expr,
367/// }
368/// ```
369///
370/// [`fmt::Debug`]: core::fmt::Debug
371/// [`ops:Not`]: core::ops::Not
372/// [`ops:BitAnd`]: core::ops::BitAnd
373/// [`ops:BitOr`]: core::ops::BitOr
374/// [`ops:BitXor`]: core::ops::BitXor
375/// [`ops:BitAndAssign`]: core::ops::BitAndAssign
376/// [`ops:BitOrAssign`]: core::ops::BitOrAssign
377/// [`ops:BitXorAssign`]: core::ops::BitXorAssign
378/// [`fmt::Binary`]: core::fmt::Binary
379/// [`fmt::LowerHex`]: core::fmt::LowerHex
380/// [`fmt::UpperHex`]: core::fmt::UpperHex
381/// [`fmt::Octal`]: core::fmt::Octal
382/// [`From`]: From
383/// [`FromStr`]: core::str::FromStr
384/// [`Default`]: core::default::Default
385/// [`IntoIterator`]: core::iter::IntoIterator
386/// [`Extend`]: core::iter::Extend
387/// [`FromIterator`]: core::iter::FromIterator
388#[proc_macro_attribute]
389pub fn bitflag(attr: TokenStream, item: TokenStream) -> TokenStream {
390    match bitflag_impl(attr, item) {
391        Ok(ts) => ts,
392        Err(err) => err.into_compile_error().into(),
393    }
394}
395
396fn bitflag_impl(attr: TokenStream, item: TokenStream) -> Result<TokenStream> {
397    let args: Args = syn::parse(attr)
398        .map_err(|err| Error::new(err.span(), "unexpected token: expected a `{integer}` type"))?;
399
400    let bitflag = Bitflag::parse(args, item)?;
401
402    Ok(bitflag.to_token_stream().into())
403}