summary refs log blame commit diff
path: root/bit_field/bit_field_derive/bit_field_derive.rs
blob: 9d9042b6838b1d0f6580439501434e56f2635e2e (plain) (tree)
1
2
3
4
5
6
7
8
9
10




                                                                         
 
                                     
                                  

                                

                                                                                                  
  

                                                        
                       



                                   
                                                                












                                                                           

 
                                                            
                                        








                                                                                   

                                                                                               
                                  
                                                             









                                                                    
                                                                                                 
                              






                                                              
         



                           
                   



                                                

     
                           





                                                           

     
                                                                
                           






                                                               
                                                                      


































                                                                                  

                                                             
                                                                        





                                 
               
                          
                   




                                               
                           

















                                                                                    
                                                                          





















                                                                   



















                                                           

                                                                                                




                                  

                                                                                               
           

     
                                          
                                                                                    












                                                             

                                   

                     
                                                       










                                              
                                                       







                          







































                                                                                    
                                                











                                                                                        

                                                                                         



                                                         
                                         
                                               


                                                            





                            
                       


                

 






                                                                                
                                                         
                                                                      
                             












                                                           




           







                                                                   


                                                     







                                                                       











                                                                      
                                                                         





                                                     
                                            









                                   
                                                                                        
                                     

                                  

     






                                                                                      
      
 
            
                  
                           
                                               
         
 

                                   

                                                                        
                       
                                                      
                 

             
     


                                              
                                                              

                                                                                    




















                                                                                                 
                           
                                                                                                

                                                                                                           

                                                                                                 
             
 
                                                                                                       

                                                                                 
                                                                                                           
                                                                                           

             

                                        
     
 


         
                                              
                                                                          

                               


                                                                                         
                           
                                                      
           


                                       
            






                                                                            
     

 
                                               
            







                                                                                    






















































                                                                       
     

 



























                                                                                                

                                                      

                         

                                                           


                         
                                                           


                              





               


                 
                         

           

                                               

                               







                               
                      
                               


                                                                                                  
                         


                                            







                                                                                                      
                                


                                                                                                         
                                 





















































                                                                                        
                                                                                                  


                                                                                                                  
                 
                                                                                                         



                                                                                                                  
                 
                                                                                                  



                                                                                                                 
                 
                                                                                                         




                                                                                                                 
                 
                                                                                                  




                                                                                                                 
                 
                                                                                                         





                                                                                                                 

                 








                                                                                

          



                                                       

     
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#![recursion_limit = "256"]

use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned};
use syn::parse::{Error, Result};
use syn::{
    parse_macro_input, Attribute, Data, DataEnum, DeriveInput, Fields, FieldsNamed, FieldsUnnamed,
    Ident, Lit, LitInt, Meta, Type, Visibility,
};

/// The function that derives the actual implementation.
#[proc_macro_attribute]
pub fn bitfield(
    _args: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let derive_input = parse_macro_input!(input as DeriveInput);

    let expanded = bitfield_impl(&derive_input).unwrap_or_else(|err| {
        let compile_error = err.to_compile_error();
        quote! {
            #compile_error

            // Include the original input to avoid "use of undeclared type"
            // errors elsewhere.
            #derive_input
        }
    });

    expanded.into()
}

fn bitfield_impl(ast: &DeriveInput) -> Result<TokenStream> {
    if !ast.generics.params.is_empty() {
        return Err(Error::new(
            Span::call_site(),
            "#[bitfield] does not support generic parameters",
        ));
    }

    match &ast.data {
        Data::Struct(data_struct) => match &data_struct.fields {
            Fields::Named(fields_named) => bitfield_struct_impl(ast, fields_named),
            Fields::Unnamed(fields_unnamed) => bitfield_tuple_struct_impl(ast, fields_unnamed),
            Fields::Unit => Err(Error::new(
                Span::call_site(),
                "#[bitfield] does not work with unit struct",
            )),
        },
        Data::Enum(data_enum) => bitfield_enum_impl(ast, data_enum),
        Data::Union(_) => Err(Error::new(
            Span::call_site(),
            "#[bitfield] does not support unions",
        )),
    }
}

fn bitfield_tuple_struct_impl(ast: &DeriveInput, fields: &FieldsUnnamed) -> Result<TokenStream> {
    let mut ast = ast.clone();
    let width = match parse_remove_bits_attr(&mut ast)? {
        Some(w) => w,
        None => {
            return Err(Error::new(
                Span::call_site(),
                "tuple struct field must have bits attribute",
            ));
        }
    };

    let ident = &ast.ident;

    if width > 64 {
        return Err(Error::new(
            Span::call_site(),
            "max width of bitfield field is 64",
        ));
    }

    let bits = width as u8;

    if fields.unnamed.len() != 1 {
        return Err(Error::new(
            Span::call_site(),
            "tuple struct field must have exactly 1 field",
        ));
    }

    let field_type = match &fields.unnamed.first().unwrap().ty {
        Type::Path(t) => t,
        _ => {
            return Err(Error::new(
                Span::call_site(),
                "tuple struct field must have primitive field",
            ));
        }
    };
    let span = field_type.path.segments.first().unwrap().ident.span();

    let from_u64 = quote_spanned! {
        span => val as #field_type
    };

    let into_u64 = quote_spanned! {
        span => val.0 as u64
    };

    let expanded = quote! {
        #ast

        impl bit_field::BitFieldSpecifier for #ident {
            const FIELD_WIDTH: u8 = #bits;
            type SetterType = Self;
            type GetterType = Self;

            #[inline]
            fn from_u64(val: u64) -> Self::GetterType {
                Self(#from_u64)
            }

            #[inline]
            fn into_u64(val: Self::SetterType) -> u64 {
                #into_u64
            }
        }
    };

    Ok(expanded)
}

fn bitfield_enum_impl(ast: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
    let mut ast = ast.clone();
    let width = parse_remove_bits_attr(&mut ast)?;
    match width {
        None => bitfield_enum_without_width_impl(&ast, data),
        Some(width) => bitfield_enum_with_width_impl(&ast, data, width),
    }
}

fn bitfield_enum_with_width_impl(
    ast: &DeriveInput,
    data: &DataEnum,
    width: u64,
) -> Result<TokenStream> {
    if width > 64 {
        return Err(Error::new(
            Span::call_site(),
            "max width of bitfield enum is 64",
        ));
    }
    let bits = width as u8;
    let declare_discriminants = get_declare_discriminants_for_enum(bits, ast, data);

    let ident = &ast.ident;
    let type_name = ident.to_string();
    let variants = &data.variants;
    let match_discriminants = variants.iter().map(|variant| {
        let variant = &variant.ident;
        quote! {
            discriminant::#variant => Ok(#ident::#variant),
        }
    });

    let expanded = quote! {
        #ast

        impl bit_field::BitFieldSpecifier for #ident {
            const FIELD_WIDTH: u8 = #bits;
            type SetterType = Self;
            type GetterType = std::result::Result<Self, bit_field::Error>;

            #[inline]
            fn from_u64(val: u64) -> Self::GetterType {
                struct discriminant;
                impl discriminant {
                    #(#declare_discriminants)*
                }
                match val {
                    #(#match_discriminants)*
                    v => Err(bit_field::Error::new(#type_name, v)),
                }
            }

            #[inline]
            fn into_u64(val: Self::SetterType) -> u64 {
                val as u64
            }
        }
    };

    Ok(expanded)
}
// Expand to an impl of BitFieldSpecifier for an enum like:
//
//     #[bitfield]
//     #[derive(Debug, PartialEq)]
//     enum TwoBits {
//         Zero = 0b00,
//         One = 0b01,
//         Two = 0b10,
//         Three = 0b11,
//     }
//
// Such enums may be used as a field of a bitfield struct.
//
//     #[bitfield]
//     struct Struct {
//         prefix: BitField1,
//         two_bits: TwoBits,
//         suffix: BitField5,
//     }
//
fn bitfield_enum_without_width_impl(ast: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
    let ident = &ast.ident;
    let variants = &data.variants;
    let len = variants.len();
    if len.count_ones() != 1 {
        return Err(Error::new(
            Span::call_site(),
            "#[bitfield] expected a number of variants which is a power of 2 when bits is not \
             specified for the enum",
        ));
    }

    let bits = len.trailing_zeros() as u8;
    let declare_discriminants = get_declare_discriminants_for_enum(bits, ast, data);

    let match_discriminants = variants.iter().map(|variant| {
        let variant = &variant.ident;
        quote! {
            discriminant::#variant => #ident::#variant,
        }
    });

    let expanded = quote! {
        #ast

        impl bit_field::BitFieldSpecifier for #ident {
            const FIELD_WIDTH: u8 = #bits;
            type SetterType = Self;
            type GetterType = Self;

            #[inline]
            fn from_u64(val: u64) -> Self::GetterType {
                struct discriminant;
                impl discriminant {
                    #(#declare_discriminants)*
                }
                match val {
                    #(#match_discriminants)*
                    _ => unreachable!(),
                }
            }

            #[inline]
            fn into_u64(val: Self::SetterType) -> u64 {
                val as u64
            }
        }
    };

    Ok(expanded)
}

fn get_declare_discriminants_for_enum(
    bits: u8,
    ast: &DeriveInput,
    data: &DataEnum,
) -> Vec<TokenStream> {
    let variants = &data.variants;
    let upper_bound = 2u64.pow(bits as u32);
    let ident = &ast.ident;

    variants
        .iter()
        .map(|variant| {
            let variant = &variant.ident;
            let span = variant.span();

            let assertion = quote_spanned! {span=>
                // If IS_IN_BOUNDS is true, this evaluates to 0.
                //
                // If IS_IN_BOUNDS is false, this evaluates to `0 - 1` which
                // triggers a compile error on underflow when referenced below. The
                // error is not beautiful but does carry the span of the problematic
                // enum variant so at least it points to the right line.
                //
                //     error: any use of this value will cause an error
                //       --> bit_field/test.rs:10:5
                //        |
                //     10 |     OutOfBounds = 0b111111,
                //        |     ^^^^^^^^^^^ attempt to subtract with overflow
                //        |
                //
                //     error[E0080]: erroneous constant used
                //      --> bit_field/test.rs:5:1
                //       |
                //     5 | #[bitfield]
                //       | ^^^^^^^^^^^ referenced constant has errors
                //
                const ASSERT: u64 = 0 - !IS_IN_BOUNDS as u64;
            };

            quote! {
                #[allow(non_upper_case_globals)]
                const #variant: u64 = {
                    const IS_IN_BOUNDS: bool = (#ident::#variant as u64) < #upper_bound;

                    #assertion

                    #ident::#variant as u64 + ASSERT
                };
            }
        })
        .collect()
}

fn bitfield_struct_impl(ast: &DeriveInput, fields: &FieldsNamed) -> Result<TokenStream> {
    let name = &ast.ident;
    let vis = &ast.vis;
    let attrs = &ast.attrs;
    let fields = get_struct_fields(fields)?;
    let struct_def = get_struct_def(vis, &name, &fields);
    let bits_impl = get_bits_impl(&name);
    let fields_impl = get_fields_impl(&fields);
    let debug_fmt_impl = get_debug_fmt_impl(&name, &fields);

    let expanded = quote! {
        #(#attrs)*
        #struct_def
        #bits_impl
        impl #name {
            #(#fields_impl)*
        }
        #debug_fmt_impl
    };

    Ok(expanded)
}

struct FieldSpec<'a> {
    ident: &'a Ident,
    ty: &'a Type,
    expected_bits: Option<LitInt>,
}

// Unwrap ast to get the named fields. We only care about field names and types:
// "myfield : BitField3" -> ("myfield", Token(BitField3))
fn get_struct_fields(fields: &FieldsNamed) -> Result<Vec<FieldSpec>> {
    let mut vec = Vec::new();

    for field in &fields.named {
        let ident = field
            .ident
            .as_ref()
            .expect("Fields::Named has named fields");
        let ty = &field.ty;
        let expected_bits = parse_bits_attr(&field.attrs)?;
        vec.push(FieldSpec {
            ident,
            ty,
            expected_bits,
        });
    }

    Ok(vec)
}

// For example: #[bits = 1]
fn parse_bits_attr(attrs: &[Attribute]) -> Result<Option<LitInt>> {
    let mut expected_bits = None;

    for attr in attrs {
        if attr.path.is_ident("doc") {
            continue;
        }
        if let Some(v) = try_parse_bits_attr(attr)? {
            expected_bits = Some(v);
            continue;
        }

        return Err(Error::new_spanned(attr, "unrecognized attribute"));
    }

    Ok(expected_bits)
}

// This function will return None if the attribute is not #[bits = *].
fn try_parse_bits_attr(attr: &Attribute) -> Result<Option<LitInt>> {
    if attr.path.is_ident("bits") {
        if let Meta::NameValue(name_value) = attr.parse_meta()? {
            if let Lit::Int(int) = name_value.lit {
                return Ok(Some(int));
            }
        }
    }
    Ok(None)
}

fn parse_remove_bits_attr(ast: &mut DeriveInput) -> Result<Option<u64>> {
    let mut width = None;
    let mut bits_idx = 0;

    for (i, attr) in ast.attrs.iter().enumerate() {
        if let Some(w) = try_parse_bits_attr(attr)? {
            bits_idx = i;
            width = Some(w.base10_parse()?);
        }
    }

    if width.is_some() {
        ast.attrs.remove(bits_idx);
    }

    Ok(width)
}

fn get_struct_def(vis: &Visibility, name: &Ident, fields: &[FieldSpec]) -> TokenStream {
    let mut field_types = Vec::new();
    for spec in fields {
        field_types.push(spec.ty);
    }

    // `(BitField1::FIELD_WIDTH + BitField3::FIELD_WIDTH + ...)`
    let data_size_in_bits = quote! {
        (
            #(
                <#field_types as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
            )+*
        )
    };

    quote! {
        #[repr(C)]
        #vis struct #name {
            data: [u8; #data_size_in_bits / 8],
        }

        impl #name {
            pub fn new() -> #name {
                let _: ::bit_field::Check<[u8; #data_size_in_bits % 8]>;

                #name {
                    data: [0; #data_size_in_bits / 8],
                }
            }
        }
    }
}

// Implement setter and getter for all fields.
fn get_fields_impl(fields: &[FieldSpec]) -> Vec<TokenStream> {
    let mut impls = Vec::new();
    // This vec keeps track of types before this field, used to generate the offset.
    let current_types = &mut vec![quote!(::bit_field::BitField0)];

    for spec in fields {
        let ty = spec.ty;
        let getter_ident = Ident::new(format!("get_{}", spec.ident).as_str(), Span::call_site());
        let setter_ident = Ident::new(format!("set_{}", spec.ident).as_str(), Span::call_site());

        // Optional #[bits = N] attribute to provide compile-time checked
        // documentation of how many bits some field covers.
        let check_expected_bits = spec.expected_bits.as_ref().map(|expected_bits| {
            // If expected_bits does not match the actual number of bits in the
            // bit field specifier, this will fail to compile with an error
            // pointing into the #[bits = N] attribute.
            let span = expected_bits.span();
            quote_spanned! {span=>
                #[allow(dead_code)]
                const EXPECTED_BITS: [(); #expected_bits as usize] =
                    [(); <#ty as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize];
            }
        });

        impls.push(quote! {
            pub fn #getter_ident(&self) -> <#ty as ::bit_field::BitFieldSpecifier>::GetterType {
                #check_expected_bits
                let offset = #(<#current_types as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)+*;
                let val = self.get(offset, <#ty as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
                <#ty as ::bit_field::BitFieldSpecifier>::from_u64(val)
            }

            pub fn #setter_ident(&mut self, val: <#ty as ::bit_field::BitFieldSpecifier>::SetterType) {
                let val = <#ty as ::bit_field::BitFieldSpecifier>::into_u64(val);
                debug_assert!(val <= ::bit_field::max::<#ty>());
                let offset = #(<#current_types as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)+*;
                self.set(offset, <#ty as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
            }
        });

        current_types.push(quote!(#ty));
    }

    impls
}

// Implement setter and getter for all fields.
fn get_debug_fmt_impl(name: &Ident, fields: &[FieldSpec]) -> TokenStream {
    // print fields:
    let mut impls = Vec::new();
    for spec in fields {
        let field_name = spec.ident.to_string();
        let getter_ident = Ident::new(&format!("get_{}", spec.ident), Span::call_site());
        impls.push(quote! {
            .field(#field_name, &self.#getter_ident())
        });
    }

    let name_str = format!("{}", name);
    quote! {
        impl std::fmt::Debug for #name {
            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                f.debug_struct(#name_str)
                #(#impls)*
                    .finish()
            }
        }
    }
}

fn get_bits_impl(name: &Ident) -> TokenStream {
    quote! {
        impl #name {
            #[inline]
            fn check_access(&self, offset: usize, width: u8) {
                debug_assert!(width <= 64);
                debug_assert!(offset / 8 < self.data.len());
                debug_assert!((offset + (width as usize)) <= (self.data.len() * 8));
            }

            #[inline]
            pub fn get_bit(&self, offset: usize) -> bool {
                self.check_access(offset, 1);

                let byte_index = offset / 8;
                let bit_offset = offset % 8;

                let byte = self.data[byte_index];
                let mask = 1 << bit_offset;

                byte & mask == mask
            }

            #[inline]
            pub fn set_bit(&mut self, offset: usize, val: bool) {
                self.check_access(offset, 1);

                let byte_index = offset / 8;
                let bit_offset = offset % 8;

                let byte = &mut self.data[byte_index];
                let mask = 1 << bit_offset;

                if val {
                    *byte |= mask;
                } else {
                    *byte &= !mask;
                }
            }

            #[inline]
            pub fn get(&self, offset: usize, width: u8) -> u64 {
                self.check_access(offset, width);
                let mut val = 0;

                for i in 0..(width as usize) {
                    if self.get_bit(i + offset) {
                        val |= 1 << i;
                    }
                }

                val
            }

            #[inline]
            pub fn set(&mut self, offset: usize, width: u8, val: u64) {
                self.check_access(offset, width);

                for i in 0..(width as usize) {
                    let mask = 1 << i;
                    let val_bit_is_set = val & mask == mask;
                    self.set_bit(i + offset, val_bit_is_set);
                }
            }
        }
    }
}

// Only intended to be used from the bit_field crate. This macro emits the
// marker types bit_field::BitField0 through bit_field::BitField64.
#[proc_macro]
#[doc(hidden)]
pub fn define_bit_field_specifiers(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let mut code = TokenStream::new();

    for width in 0u8..=64 {
        let span = Span::call_site();
        let long_name = Ident::new(&format!("BitField{}", width), span);
        let short_name = Ident::new(&format!("B{}", width), span);

        let default_field_type = if width <= 8 {
            quote!(u8)
        } else if width <= 16 {
            quote!(u16)
        } else if width <= 32 {
            quote!(u32)
        } else {
            quote!(u64)
        };

        code.extend(quote! {
            pub struct #long_name;
            pub use self::#long_name as #short_name;

            impl BitFieldSpecifier for #long_name {
                const FIELD_WIDTH: u8 = #width;
                type SetterType = #default_field_type;
                type GetterType = #default_field_type;

                #[inline]
                fn from_u64(val: u64) -> Self::GetterType {
                    val as Self::GetterType
                }

                #[inline]
                fn into_u64(val: Self::SetterType) -> u64 {
                    val as u64
                }
            }
        });
    }

    code.into()
}

#[cfg(test)]
mod tests {
    use super::*;
    use syn::parse_quote;

    #[test]
    fn end_to_end() {
        let input: DeriveInput = parse_quote! {
            #[derive(Clone)]
            struct MyBitField {
                a: BitField1,
                b: BitField2,
                c: BitField5,
            }
        };

        let expected = quote! {
            #[derive(Clone)]
            #[repr(C)]
            struct MyBitField {
                data: [u8; (<BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                            + <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                            + <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)
                    / 8],
            }
            impl MyBitField {
                pub fn new() -> MyBitField {
                    let _: ::bit_field::Check<[
                        u8;
                        (<BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                                + <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                                + <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)
                            % 8
                    ]>;

                    MyBitField {
                        data: [0; (<BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                                   + <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                                   + <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize)
                            / 8],
                    }
                }
            }
            impl MyBitField {
                #[inline]
                fn check_access(&self, offset: usize, width: u8) {
                    debug_assert!(width <= 64);
                    debug_assert!(offset / 8 < self.data.len());
                    debug_assert!((offset + (width as usize)) <= (self.data.len() * 8));
                }
                #[inline]
                pub fn get_bit(&self, offset: usize) -> bool {
                    self.check_access(offset, 1);
                    let byte_index = offset / 8;
                    let bit_offset = offset % 8;
                    let byte = self.data[byte_index];
                    let mask = 1 << bit_offset;
                    byte & mask == mask
                }
                #[inline]
                pub fn set_bit(&mut self, offset: usize, val: bool) {
                    self.check_access(offset, 1);
                    let byte_index = offset / 8;
                    let bit_offset = offset % 8;
                    let byte = &mut self.data[byte_index];
                    let mask = 1 << bit_offset;
                    if val {
                        *byte |= mask;
                    } else {
                        *byte &= !mask;
                    }
                }
                #[inline]
                pub fn get(&self, offset: usize, width: u8) -> u64 {
                    self.check_access(offset, width);
                    let mut val = 0;
                    for i in 0..(width as usize) {
                        if self.get_bit(i + offset) {
                            val |= 1 << i;
                        }
                    }
                    val
                }
                #[inline]
                pub fn set(&mut self, offset: usize, width: u8, val: u64) {
                    self.check_access(offset, width);
                    for i in 0..(width as usize) {
                        let mask = 1 << i;
                        let val_bit_is_set = val & mask == mask;
                        self.set_bit(i + offset, val_bit_is_set);
                    }
                }
            }
            impl MyBitField {
                pub fn get_a(&self) -> <BitField1 as ::bit_field::BitFieldSpecifier>::GetterType {
                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
                    let val = self.get(offset, <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
                    <BitField1 as ::bit_field::BitFieldSpecifier>::from_u64(val)
                }
                pub fn set_a(&mut self, val: <BitField1 as ::bit_field::BitFieldSpecifier>::SetterType) {
                    let val = <BitField1 as ::bit_field::BitFieldSpecifier>::into_u64(val);
                    debug_assert!(val <= ::bit_field::max::<BitField1>());
                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
                    self.set(offset, <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
                }
                pub fn get_b(&self) -> <BitField2 as ::bit_field::BitFieldSpecifier>::GetterType {
                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                        + <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
                    let val = self.get(offset, <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
                    <BitField2 as ::bit_field::BitFieldSpecifier>::from_u64(val)
                }
                pub fn set_b(&mut self, val: <BitField2 as ::bit_field::BitFieldSpecifier>::SetterType) {
                    let val = <BitField2 as ::bit_field::BitFieldSpecifier>::into_u64(val);
                    debug_assert!(val <= ::bit_field::max::<BitField2>());
                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                        + <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
                    self.set(offset, <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
                }
                pub fn get_c(&self) -> <BitField5 as ::bit_field::BitFieldSpecifier>::GetterType {
                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                        + <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                        + <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
                    let val = self.get(offset, <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH);
                    <BitField5 as ::bit_field::BitFieldSpecifier>::from_u64(val)
                }
                pub fn set_c(&mut self, val: <BitField5 as ::bit_field::BitFieldSpecifier>::SetterType) {
                    let val = <BitField5 as ::bit_field::BitFieldSpecifier>::into_u64(val);
                    debug_assert!(val <= ::bit_field::max::<BitField5>());
                    let offset = <::bit_field::BitField0 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                        + <BitField1 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize
                        + <BitField2 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH as usize;
                    self.set(offset, <BitField5 as ::bit_field::BitFieldSpecifier>::FIELD_WIDTH, val)
                }
            }
            impl std::fmt::Debug for MyBitField {
                fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
                    f.debug_struct("MyBitField")
                        .field("a", &self.get_a())
                        .field("b", &self.get_b())
                        .field("c", &self.get_c())
                        .finish()
                }
            }
        };

        assert_eq!(
            bitfield_impl(&input).unwrap().to_string(),
            expected.to_string()
        );
    }
}