bilge-impl 0.3.0

Use bitsized types as if they were a feature of rust.
Documentation
use proc_macro2::{Ident, TokenStream};
use proc_macro_error2::abort_call_site;
use quote::quote;
use syn::{Data, Fields};

use crate::shared::{self, unreachable};

pub(super) fn debug_bits(item: TokenStream) -> TokenStream {
    let derive_input = shared::parse_derive(item);
    let name = &derive_input.ident;
    let name_str = name.to_string();
    let struct_data = match derive_input.data {
        Data::Struct(s) => s,
        Data::Enum(_) => abort_call_site!("use derive(Debug) for enums"),
        Data::Union(_) => unreachable(()),
    };

    let fmt_impl = match struct_data.fields {
        Fields::Named(fields) => {
            let calls = fields.named.iter().map(|f| {
                // We can unwrap since this is a named field
                let call = f.ident.as_ref().unwrap();
                let name = call.to_string();
                quote!(.field(#name, &self.#call()))
            });
            quote! {
                f.debug_struct(#name_str)
                // .field("field1", &self.field1()).field("field2", &self.field2()).field("field3", &self.field3()).finish()
                #(#calls)*.finish()
            }
        }
        Fields::Unnamed(fields) => {
            let calls = fields.unnamed.iter().enumerate().map(|(i, _)| {
                let call: Ident = syn::parse_str(&format!("val_{i}")).unwrap_or_else(unreachable);
                quote!(.field(&self.#call()))
            });
            quote! {
                f.debug_tuple(#name_str)
                // .field(&self.val0()).field(&self.val1()).finish()
                #(#calls)*.finish()
            }
        }
        Fields::Unit => todo!("this is a unit struct, which is not supported right now"),
    };

    quote! {
        impl ::core::fmt::Debug for #name {
            fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
                #fmt_impl
            }
        }
    }
}