nandi/rustnimpublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/nandi/rustnim.git
git clone ssh://git@rickub.com/nandi/rustnim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

macros.rs · 64 lines · 2.7 KBRust Blame HistoryRaw
Lower `bitflags!` directly, checked against the real crate af6e50f nandithebull 7h ago1//! Shims for macros whose expansion cannot usefully be followed.
2//!
3//! The general rule in this project is that a macro whose expansion is not
4//! known is rejected. `bitflags!` is an argued exception, and the argument is
5//! this: expanding it does not help. `cargo rustc -Zunpretty=expanded` on a
6//! one-flag user produces 869 lines that still call into
7//! `bitflags::{Bits, Flag, Flags, iter, parser}` — which are themselves
8//! defined by 26 further `macro_rules!` across five files. The chain does not
9//! terminate in code we could lower.
10//!
11//! What the macro *means*, though, is small, documented and stable: a newtype
12//! over an integer with named constants and set operations. So it is lowered
13//! directly. That is not approximating a semantic we cannot represent — it is
14//! implementing one we can, and `tests/cases/034-bitflags.rs` checks the
15//! result against the real crate rather than against this comment.
16//!
17//! Verified against bitflags 2.13.2. Two behaviours are worth naming because
18//! they are not what a reimplementation would guess: `!x` is complemented and
19//! then masked to `all()`, and `from_bits` returns `None` for any bit outside
20//! `all()`.
21
22use syn::parse::{Parse, ParseStream};
23use syn::{braced, Expr, Ident, Token, Type, Visibility};
24
25/// One `pub struct Name: Repr { const A = ..; }` inside a `bitflags!`.
26pub struct FlagsDef {
27 pub name: Ident,
28 pub repr: Type,
29 pub flags: Vec<(Ident, Expr)>,
30}
31
32/// The whole macro body, which may declare more than one type.
33pub struct BitflagsInput(pub Vec<FlagsDef>);
34
35impl Parse for BitflagsInput {
36 fn parse(input: ParseStream) -> syn::Result<Self> {
37 let mut out = Vec::new();
38 while !input.is_empty() {
39 // Attributes on the struct (`#[derive(..)]`) carry no meaning we
40 // need: the operations they derive are generated regardless.
41 let _ = input.call(syn::Attribute::parse_outer)?;
42 let _: Visibility = input.parse()?;
43 input.parse::<Token![struct]>()?;
44 let name: Ident = input.parse()?;
45 input.parse::<Token![:]>()?;
46 let repr: Type = input.parse()?;
47
48 let body;
49 braced!(body in input);
50 let mut flags = Vec::new();
51 while !body.is_empty() {
52 let _ = body.call(syn::Attribute::parse_outer)?;
53 body.parse::<Token![const]>()?;
54 let fname: Ident = body.parse()?;
55 body.parse::<Token![=]>()?;
56 let value: Expr = body.parse()?;
57 body.parse::<Token![;]>()?;
58 flags.push((fname, value));
59 }
60 out.push(FlagsDef { name, repr, flags });
61 }
62 Ok(BitflagsInput(out))
63 }
64}