bitfield_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{
4    ext::IdentExt,
5    parenthesized,
6    parse::{discouraged::Speculative, Parse, ParseStream},
7    parse_macro_input, Attribute, Expr, Ident, Token, Type, Visibility,
8};
9
10mod kw {
11    use syn::custom_keyword;
12
13    custom_keyword!(bool);
14    custom_keyword!(from);
15    custom_keyword!(getter);
16    custom_keyword!(into);
17    custom_keyword!(try_into);
18    custom_keyword!(mask);
19    custom_keyword!(only);
20    custom_keyword!(setter);
21}
22
23// We use Bitfield in the structs/enums names to avoid confusion with the types from syn/std
24
25struct BitfieldMask {
26    ident: Ident,
27    ty: Type,
28}
29
30impl Parse for BitfieldMask {
31    fn parse(input: ParseStream) -> syn::Result<Self> {
32        let ident = input.parse()?;
33        let paren_content;
34        parenthesized!(paren_content in input);
35        let ty = paren_content.parse()?;
36        Ok(BitfieldMask { ident, ty })
37    }
38}
39
40enum BitfieldPosition {
41    Bit(Expr),
42    MsbLsb(Expr, Expr),
43    MsbLsbCount(Expr, Expr, Expr),
44}
45
46impl Parse for BitfieldPosition {
47    fn parse(input: ParseStream) -> syn::Result<Self> {
48        let bit_position_1 = input.parse()?;
49        if !input.peek(Token!(,)) {
50            return Ok(BitfieldPosition::Bit(bit_position_1));
51        }
52        input.parse::<Token!(,)>()?;
53        let bit_position_2 = input.parse()?;
54        if !input.peek(Token!(,)) {
55            return Ok(BitfieldPosition::MsbLsb(bit_position_1, bit_position_2));
56        }
57        input.parse::<Token!(,)>()?;
58        let bit_position_3 = input.parse()?;
59
60        Ok(BitfieldPosition::MsbLsbCount(
61            bit_position_1,
62            bit_position_2,
63            bit_position_3,
64        ))
65    }
66}
67
68enum FieldTy {
69    Bool,
70    Type(Type),
71    None,
72}
73
74impl FieldTy {
75    fn as_type(&self) -> Option<Type> {
76        match self {
77            FieldTy::Bool => Some(syn::parse_str("bool").unwrap()),
78            FieldTy::Type(ty) => Some(ty.clone()),
79            FieldTy::None => None,
80        }
81    }
82
83    fn is_none(&self) -> bool {
84        matches!(self, FieldTy::None)
85    }
86}
87
88impl From<Option<Type>> for FieldTy {
89    fn from(value: Option<Type>) -> Self {
90        match value {
91            Some(ty) => FieldTy::Type(ty),
92            None => FieldTy::None,
93        }
94    }
95}
96
97struct BitfieldField {
98    attrs: Vec<Attribute>,
99    vis: Visibility,
100    ty: FieldTy,
101    mask: Option<BitfieldMask>,
102    from: bool,
103    into: bool,
104    try_into: bool,
105    from_into_ty: Option<Type>,
106    getter: Ident,
107    setter: Ident,
108    bits_position: BitfieldPosition,
109}
110
111impl BitfieldField {
112    fn ty_from(&self) -> Option<Type> {
113        if self.from {
114            self.from_into_ty.clone()
115        } else {
116            self.ty.as_type()
117        }
118    }
119
120    fn ty_into(&self) -> Option<Type> {
121        if self.into || self.try_into {
122            self.from_into_ty.clone()
123        } else {
124            self.ty.as_type()
125        }
126    }
127}
128
129impl Parse for BitfieldField {
130    fn parse(input: ParseStream) -> syn::Result<Self> {
131        let attrs = input.call(Attribute::parse_outer)?;
132        let vis = input.parse()?;
133        let mut ty = FieldTy::None;
134        if input.peek(kw::bool) && input.peek2(Token!(,)) {
135            input.parse::<kw::bool>()?;
136            ty = FieldTy::Bool;
137            input.parse::<Token!(,)>()?;
138        } else {
139            let input_fork = input.fork();
140            if let Ok(parsed_ty) = input_fork.parse() {
141                if input_fork.peek(Token!(,)) && !input_fork.peek3(Token!(:)) {
142                    ty = FieldTy::Type(parsed_ty);
143                    input.advance_to(&input_fork);
144                    input.parse::<Token!(,)>()?;
145                }
146            }
147        };
148
149        let mut mask = None;
150        // We check for a comma after the keyword to differentiate the case where the keyword is in
151        // fact the getter name and the normal use of the keyword.
152        if input.peek(kw::mask) && !input.peek2(Token!(,)) {
153            input.parse::<kw::mask>()?;
154            mask = Some(input.parse()?);
155            input.parse::<Token!(,)>()?;
156        }
157
158        let from = input.peek(kw::from) && !input.peek2(Token!(,));
159        if from {
160            input.parse::<kw::from>()?;
161        }
162
163        let into = input.peek(kw::into) && !input.peek2(Token!(,));
164
165        let mut try_into = false;
166        if into {
167            input.parse::<kw::into>()?;
168        } else {
169            try_into = input.peek(kw::try_into) && !input.peek2(Token!(,));
170            if try_into {
171                input.parse::<kw::try_into>()?;
172            }
173        }
174
175        let mut from_into_ty = None;
176        if from || into || try_into {
177            from_into_ty = Some(input.parse()?);
178            input.parse::<Token!(,)>()?;
179        };
180
181        let getter = input.call(Ident::parse_any)?;
182        input.parse::<Token!(,)>()?;
183        let setter = input.call(Ident::parse_any)?;
184        input.parse::<Token!(:)>()?;
185        let bits_position = input.parse()?;
186
187        Ok(BitfieldField {
188            attrs,
189            vis,
190            ty,
191            mask,
192            from,
193            into,
194            try_into,
195            from_into_ty,
196            getter,
197            setter,
198            bits_position,
199        })
200    }
201}
202
203enum BitfieldFieldLine {
204    NewDefaultType(Type),
205    Field(BitfieldField),
206}
207
208impl Parse for BitfieldFieldLine {
209    fn parse(input: ParseStream) -> syn::Result<Self> {
210        let input_fork = input.fork();
211
212        Ok(match input_fork.parse() {
213            // check if we have a single type statement either terminated by a semicolon or the
214            // end of the stream, but do not consume the semicolon
215            Ok(ty) if (input_fork.is_empty() || input_fork.peek(Token!(;))) => {
216                input.advance_to(&input_fork);
217                BitfieldFieldLine::NewDefaultType(ty)
218            }
219            _ => BitfieldFieldLine::Field(input.parse()?),
220        })
221    }
222}
223
224struct BitfieldFieldLines(Vec<BitfieldFieldLine>);
225
226impl BitfieldFieldLines {
227    fn into_fields(self) -> Vec<BitfieldField> {
228        let mut result = vec![];
229        let mut default_ty = None;
230        for line in self.0 {
231            match line {
232                BitfieldFieldLine::NewDefaultType(ty) => default_ty = Some(ty),
233                BitfieldFieldLine::Field(mut field) => {
234                    if field.ty.is_none() {
235                        field.ty = default_ty.clone().into();
236                    }
237                    result.push(field)
238                }
239            }
240        }
241
242        result
243    }
244}
245
246impl Parse for BitfieldFieldLines {
247    fn parse(input: ParseStream) -> syn::Result<Self> {
248        let field_lines = input
249            .parse_terminated(BitfieldFieldLine::parse, Token!(;))?
250            .into_iter()
251            .collect();
252
253        Ok(BitfieldFieldLines(field_lines))
254    }
255}
256
257#[derive(Copy, Clone, Eq, PartialEq)]
258enum Only {
259    Getter,
260    Mask,
261    Setter,
262    None,
263}
264
265impl Only {
266    fn getter_or_none(&self) -> bool {
267        *self == Only::Getter || *self == Only::None
268    }
269
270    fn mask_or_none(&self) -> bool {
271        *self == Only::Mask || *self == Only::None
272    }
273
274    fn setter_or_none(&self) -> bool {
275        *self == Only::Setter || *self == Only::None
276    }
277}
278
279struct BitfieldFieldsWithOnly {
280    only: Only,
281    fields: BitfieldFieldLines,
282}
283
284impl Parse for BitfieldFieldsWithOnly {
285    fn parse(input: ParseStream) -> syn::Result<Self> {
286        let only = if input.peek(kw::only) {
287            input.parse::<kw::only>()?;
288            let only = if input.peek(kw::getter) {
289                input.parse::<kw::getter>()?;
290                Only::Getter
291            } else if input.peek(kw::setter) {
292                input.parse::<kw::setter>()?;
293                Only::Setter
294            } else if input.peek(kw::mask) {
295                input.parse::<kw::mask>()?;
296                Only::Mask
297            } else {
298                return Err(input
299                    .error("after the only keyword, either getter, mask or setter is expected"));
300            };
301            input.parse::<Token!(;)>()?;
302            only
303        } else {
304            Only::None
305        };
306        let fields = input.parse()?;
307
308        Ok(BitfieldFieldsWithOnly { only, fields })
309    }
310}
311
312/// Declares the fields of a struct.
313///
314/// This macro will generate the methods to access the fields of a bitfield. It must be called
315/// from an `impl` block for a type that implements the `BitRange` and/or the `Bit` traits
316/// (which traits are required depending on what type of fields are used).
317///
318/// The syntax of this macro is composed of declarations ended by semicolons. There are two types
319/// of declarations: default type, and fields.
320///
321/// A default type is just a type followed by a semicolon. This will affect all the following field
322/// declarations.
323///
324/// A field declaration is composed of the following:
325///
326/// * Optional attributes (`#[...]`), documentation comments (`///`) are attributes;
327/// * An optional pub keyword to make the methods public
328/// * An optional type followed by a comma
329/// * Optionnaly, the word `mask` followed by an identifier and an type in parentheses, followed by
330///   a comma
331/// * Optionally, the word `from` and/or (`into` or `try_into`) followed by a type, followed by a comma
332/// * The getter and setter idents, separated by a comma
333/// * A colon
334/// * One to three expressions of type `usize`
335///
336/// The attributes and pub will be applied to the two methods generated.
337///
338/// If the `into` part is used, the getter will convert the field after reading it.
339/// If the `try_into` part is used, the getter will try to convert the field after reading it.
340///
341/// The getter and setter idents can be `_` to not generate one of the two. For example, if the
342/// setter is `_`, the field will be read-only.
343///
344/// The expressions at the end are the bit positions. Their meaning depends on the number of
345/// expressions:
346///
347///  * One expression: the field is a single bit. The type is ignored and `bool` is used. The trait
348///    `Bit` is used.
349///  * Two expressions: `msb, lsb`, the field is composed of the bits from `msb` to `lsb`, included.
350///  * Three expressions: `msb, lsb, count`, the field is an array. The first element is composed of
351///    the bits from `msb` to `lsb`. The following elements are consecutive bits range of the same
352///    size.
353///
354/// # Example
355///
356/// ```ignore
357/// # use bitfield_macros::bitfield_fields;
358/// # fn main() {}
359/// # struct FooBar(u64);
360/// # bitfield_bitrange!{struct FooBar(u64)}
361/// # impl From<u32> for FooBar{ fn from(_: u32) -> FooBar {unimplemented!()}}
362/// # impl From<FooBar> for u32{ fn from(_: FooBar) -> u32 {unimplemented!()}}
363/// # impl FooBar {
364/// bitfield_fields!{
365///     // The default type will be `u64
366///     u64;
367///     // filed1 is read-write, public, the methods are inline
368///     #[inline]
369///     pub field1, set_field1: 10, 0;
370///     // `field2` is  read-only, private, and of type bool.
371///     field2, _ : 0;
372///     // `field3` will be read as an `u32` and then converted to `FooBar`.
373///     // The setter is not affected, it still need an `u32` value.
374///     u32, into FooBar, field3, set_field3: 10, 0;
375///     // `field4` will be read as an `u32` and then converted to `FooBar`.
376///     // The setter will take a `FooBar`, and converted back to an `u32`.
377///     u32, from into FooBar, field4, set_field4: 10, 0;
378///     // `field5` will be read as an `u32` and then converted to `FooBar`.
379///     // The setter will take a `FooBar`, and converted back to an `u32`.
380///     // The struct will have an associated constant `FIELD5_MASK` of type u64
381///     //with the bits of field5 set
382///     u32, mask FIELD5_MASK(u64), from into FooBar, field5, set_field5: 10, 0;
383/// }
384/// # }
385/// ```
386#[proc_macro]
387pub fn bitfield_fields(input: TokenStream) -> TokenStream {
388    let fields_with_only = parse_macro_input!(input as BitfieldFieldsWithOnly);
389
390    let only = fields_with_only.only;
391    let fields = fields_with_only.fields.into_fields();
392
393    let getters = if only.getter_or_none() {
394        generate_getters(&fields)
395    } else {
396        quote! {}
397    };
398
399    let setters = if only.setter_or_none() {
400        generate_setters(&fields)
401    } else {
402        quote! {}
403    };
404
405    let masks = if only.mask_or_none() {
406        generate_masks(&fields)
407    } else {
408        quote! {}
409    };
410
411    let expanded = quote! {
412        #getters
413        #setters
414        #masks
415    };
416    TokenStream::from(expanded)
417}
418static MISSING_TYPE_ERROR_MESSAGE: &str =
419    "For non single bit field, you need to either specify a default type or a type for each field";
420
421fn generate_getters(fields: &[BitfieldField]) -> proc_macro2::TokenStream {
422    let getters = fields.iter().flat_map(|field| {
423        if field.getter != "_" {
424            let attrs = &field.attrs;
425            let vis = &field.vis;
426            let getter = &field.getter;
427            Some(match &field.bits_position {
428                BitfieldPosition::Bit(bit) => {
429                    quote! {
430                        #(#attrs)*
431                        #vis fn #getter(&self) -> bool {
432                            use ::bitfield::Bit;
433                            self.bit(#bit)
434                         }
435                    }
436                }
437                BitfieldPosition::MsbLsb(msb, lsb) => {
438                    let ty = field.ty.as_type().expect(MISSING_TYPE_ERROR_MESSAGE);
439                    let ty_into = field.ty_into().unwrap();
440                    if field.try_into {
441                        quote! {
442                            #(#attrs)*
443                            #vis fn #getter(&self) -> Result<#ty_into, <#ty_into as TryFrom<#ty>>::Error> {
444                                use ::bitfield::BitRange;
445                                let raw_value: #ty = self.bit_range(#msb, #lsb);
446                                ::bitfield::TryInto::try_into(raw_value)
447                            }
448                        }
449                    } else {
450                        quote! {
451                            #(#attrs)*
452                            #vis fn #getter(&self) -> #ty_into {
453                                use ::bitfield::BitRange;
454                                let raw_value: #ty = self.bit_range(#msb, #lsb);
455                                ::bitfield::Into::into(raw_value)
456                            }
457                        }
458                    }
459                }
460                BitfieldPosition::MsbLsbCount(msb, lsb, count) => match &field.ty {
461                    FieldTy::Bool => {
462                        quote! {
463                            #(#attrs)*
464                            #vis fn #getter(&self, index: usize) -> bool {
465                                use ::bitfield::Bit;
466                                assert_eq!(#msb, #lsb);
467                                use ::bitfield::BitRange;
468                                debug_assert!(index < #count);
469                                self.bit((#lsb)+index)
470                            }
471                        }
472                    }
473                    FieldTy::Type(ty) => {
474                        let ty_into = field.ty_into().unwrap();
475                        let (return_ty, last_line) = if field.try_into {
476                            (
477                                quote!{Result<#ty_into, <#ty_into as TryFrom<#ty>>::Error>}, 
478                                quote!{::bitfield::TryInto::try_into(raw_value)}
479                            )
480                        } else {
481                            (quote!{#ty_into}, quote!{::bitfield::Into::into(raw_value)})
482                        };
483                        quote! {
484                            #(#attrs)*
485                            #vis fn #getter(&self, index: usize) -> #return_ty {
486                                use ::bitfield::BitRange;
487                                ::bitfield::check_msb_lsb_order!(#msb, #lsb);
488                                debug_assert!(index < #count);
489                                #[allow(clippy::eq_op)]
490                                #[allow(clippy::identity_op)]
491                                let width = #msb - #lsb + 1;
492                                let lsb = #lsb + index*width;
493                                let msb = lsb + width - 1;
494                                let raw_value: #ty = self.bit_range(msb, lsb);
495                                #last_line
496                            }
497                        }
498                    }
499                    FieldTy::None => panic!("{}", MISSING_TYPE_ERROR_MESSAGE),
500                },
501            })
502        } else {
503            None
504        }
505    });
506    quote! { #(#getters)* }
507}
508
509fn generate_setters(fields: &[BitfieldField]) -> proc_macro2::TokenStream {
510    let setters = fields.iter().flat_map(|field| {
511        if field.setter != "_" {
512            let attrs = &field.attrs;
513            let vis = &field.vis;
514            let setter = &field.setter;
515            Some(match &field.bits_position {
516                BitfieldPosition::Bit(bit) => {
517                    quote! {
518                        #(#attrs)*
519                        #vis fn #setter(&mut self, value: bool) {
520                            use ::bitfield::BitMut;
521                            self.set_bit(#bit, value);
522                         }
523                    }
524                }
525                BitfieldPosition::MsbLsb(msb, lsb) => {
526                    let ty = field.ty.as_type().expect(MISSING_TYPE_ERROR_MESSAGE);
527                    let ty_from = field.ty_from().unwrap();
528                    quote! {
529                        #(#attrs)*
530                        #vis fn #setter(&mut self, value: #ty_from) {
531                            use ::bitfield::BitRangeMut;
532                            self.set_bit_range(#msb, #lsb, ::bitfield::Into::<#ty>::into(value));
533                         }
534                    }
535                }
536                BitfieldPosition::MsbLsbCount(msb, lsb, count) => match &field.ty {
537                    FieldTy::Bool => {
538                        let ty_from = field.ty_from().unwrap();
539                        quote! {
540                            #(#attrs)*
541                            #vis fn #setter(&mut self, index: usize, value: #ty_from) {
542                                use ::bitfield::BitMut;
543                                debug_assert!(index < #count);;
544                                self.set_bit(#lsb+index, ::bitfield::Into::<bool>::into(value));
545                             }
546                        }
547                    }
548                    FieldTy::Type(ty) => {
549                        let ty_from = field.ty_from().unwrap();
550                        quote! {
551                            #(#attrs)*
552                            #vis fn #setter(&mut self, index: usize, value: #ty_from) {
553                                use ::bitfield::BitRangeMut;
554                                ::bitfield::check_msb_lsb_order!(#msb, #lsb);
555                                debug_assert!(index < #count);
556                                #[allow(clippy::eq_op)]
557                                #[allow(clippy::identity_op)]
558                                let width = #msb - #lsb + 1;
559                                let lsb = #lsb + index*width;
560                                let msb = lsb + width - 1;
561                                self.set_bit_range(msb, lsb, ::bitfield::Into::<#ty>::into(value));
562                             }
563                        }
564                    }
565                    FieldTy::None => panic!("{}", MISSING_TYPE_ERROR_MESSAGE),
566                },
567            })
568        } else {
569            None
570        }
571    });
572    quote! { #(#setters)* }
573}
574
575fn generate_masks(fields: &[BitfieldField]) -> proc_macro2::TokenStream {
576    let masks = fields.iter().flat_map(|field| {
577        if let Some(mask) = &field.mask {
578            let vis = &field.vis;
579            let mask_ident = &mask.ident;
580            let mask_ty = &mask.ty;
581            Some(match &field.bits_position {
582                BitfieldPosition::Bit(bit) => {
583                    quote! {#vis const #mask_ident: #mask_ty = 1 << (#bit);}
584                }
585                BitfieldPosition::MsbLsb(msb, lsb) => {
586                    quote! {
587                        #vis const #mask_ident: #mask_ty = {
588                            let msb = #msb;
589                            let lsb = #lsb;
590                            let mut i = lsb;
591                            let mut acc = 0;
592                            while i <= msb {
593                                 acc |= 1<<i;
594                                 i += 1;
595                            }
596                            acc
597                        };
598                    }
599                }
600                BitfieldPosition::MsbLsbCount(msb, lsb, count) => {
601                    quote! {
602                        #vis const #mask_ident: #mask_ty = {
603                            let msb = #msb;
604                            let lsb = #lsb;
605                            let count = #count;
606                            let width = msb - lsb;
607                            let full_msb = msb + width * count;
608                            let mut i = lsb;
609                            let mut acc = 0;
610                            while i <= full_msb {
611                                acc |= 1<<i;
612                                i += 1;
613                            }
614                            acc
615                        };
616                    }
617                }
618            })
619        } else {
620            None
621        }
622    });
623    quote! { #(#masks)* }
624}
625
626/// Implements an exhaustive constructor function for a bitfield. Should only be called by `bitfield!` when using `impl new;`
627#[proc_macro]
628pub fn bitfield_constructor(input: TokenStream) -> TokenStream {
629    let fields_with_only = parse_macro_input!(input as BitfieldFieldsWithOnly);
630
631    let fields = fields_with_only.fields.into_fields();
632
633    let fields_with_setter: Vec<_> = fields
634        .into_iter()
635        .filter(|field| field.setter != "_")
636        .collect();
637    let args = fields_with_setter.iter().map(|field| {
638        let name = &field.setter;
639        match &field.bits_position {
640            BitfieldPosition::Bit(_) => {
641                quote! {
642                   #name: bool
643                }
644            }
645            BitfieldPosition::MsbLsb(_, _) => {
646                let ty_from = field.ty_from().expect(MISSING_TYPE_ERROR_MESSAGE);
647                quote! {
648                    #name: #ty_from
649                }
650            }
651            BitfieldPosition::MsbLsbCount(_, _, _) => {
652                panic!("Array fields as not supported in the `new` method generator")
653            }
654        }
655    });
656
657    let setter_idents = fields_with_setter.iter().map(|field| &field.setter);
658
659    let expanded = quote! {
660        #[allow(clippy::too_many_arguments, missing_docs)]
661        pub fn new(#(#args,)*) -> Self {
662            let mut value = Self(Default::default());
663            #(value.#setter_idents(#setter_idents);)*
664            value
665        }
666    };
667
668    TokenStream::from(expanded)
669}
670
671struct BitfieldDebugArgs {
672    name: Ident,
673    field_lines: BitfieldFieldLines,
674}
675
676impl Parse for BitfieldDebugArgs {
677    fn parse(input: ParseStream) -> syn::Result<Self> {
678        input.parse::<Token!(struct)>()?;
679        let name = input.parse()?;
680        input.parse::<Token!(;)>()?;
681        let field_lines = input.parse()?;
682
683        Ok(BitfieldDebugArgs { name, field_lines })
684    }
685}
686
687/// Generates a `fmt::Debug` implementation.
688///
689/// This macros must be called from a `impl Debug for ...` block. It will generate the `fmt` method.
690///
691/// In most of the case, you will not directly call this macros, but use `bitfield`.
692///
693/// The syntax is `struct TheNameOfTheStruct;` followed by the syntax of `bitfield_fields`.
694///
695/// The write-only fields are ignored.
696///
697/// # Example
698///
699/// ```ignore
700/// struct FooBar(u32);
701/// bitfield_bitrange!{struct FooBar(u32)}
702/// impl FooBar{
703///     bitfield_fields!{
704///        u32;
705///        field1, _: 7, 0;
706///        field2, _: 31, 24;
707///     }
708/// }
709///
710/// impl std::fmt::Debug for FooBar {
711///     bitfield_debug!{
712///        struct FooBar;
713///        field1, _: 7, 0;
714///        field2, _: 31, 24;
715///     }
716/// }
717///
718/// fn main() {
719///     let foobar = FooBar(0x11223344);
720///     println!("{:?}", foobar);
721/// }
722/// ```
723#[proc_macro]
724pub fn bitfield_debug(input: TokenStream) -> TokenStream {
725    let args = parse_macro_input!(input as BitfieldDebugArgs);
726
727    let name = args.name;
728    let fields = args.field_lines.into_fields();
729    let fields_expr = fields
730        .iter()
731        .filter(|field| field.getter != "_")
732        .map(|field| {
733            let getter = &field.getter;
734            match &field.bits_position {
735                BitfieldPosition::Bit(_) | BitfieldPosition::MsbLsb(_, _) => {
736                    quote! {
737                        debug_struct.field(stringify!(#getter), &self.#getter());
738                    }
739                }
740                BitfieldPosition::MsbLsbCount(_, _, count) => {
741                    quote! {
742                        let mut array = [self.#getter(0); #count];
743                        for (i, e) in (&mut array).into_iter().enumerate() {
744                            *e = self.#getter(i);
745                        }
746                        debug_struct.field(stringify!(#getter), &array);
747                    }
748                }
749            }
750        });
751
752    let expanded = quote! {
753        fn fmt(&self, f: &mut ::bitfield::fmt::Formatter) -> ::bitfield::fmt::Result {
754            let mut debug_struct = f.debug_struct(stringify!(#name));
755            debug_struct.field(".0", &self.0);
756            #(#fields_expr)*
757            debug_struct.finish()
758        }
759    };
760
761    TokenStream::from(expanded)
762}