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| {
let call = f.ident.as_ref().unwrap();
let name = call.to_string();
quote!(.field(#name, &self.#call()))
});
quote! {
f.debug_struct(#name_str)
#(#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)
#(#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
}
}
}
}