//! Implementation of a [`fmt::Debug`] derive macro. //! //! [`fmt::Debug`]: std::fmt::Debug
use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{
parse::{Error, Parse, ParseStream, Result},
parse_quote,
spanned::Spanned as _,
Ident,
};
usesuper::{BoundsAttribute, FmtAttribute};
/// Expands a [`fmt::Debug`] derive macro. /// /// [`fmt::Debug`]: std::fmt::Debug pubfn expand(input: &syn::DeriveInput, _: &str) -> Result<TokenStream> { let attrs = ContainerAttributes::parse_attrs(&input.attrs)?; let ident = &input.ident;
let (bounds, body) = match &input.data {
syn::Data::Struct(s) => expand_struct(attrs, ident, s),
syn::Data::Enum(e) => expand_enum(attrs, e),
syn::Data::Union(_) => { return Err(Error::new(
input.span(), "`Debug` cannot be derived for unions",
));
}
}?;
let (impl_gens, ty_gens, where_clause) = { let (impl_gens, ty_gens, where_clause) = input.generics.split_for_impl(); letmut where_clause = where_clause
.cloned()
.unwrap_or_else(|| parse_quote! { where });
where_clause.predicates.extend(bounds);
(impl_gens, ty_gens, where_clause)
};
/// Expands a [`fmt::Debug`] derive macro for the provided struct. /// /// [`fmt::Debug`]: std::fmt::Debug fn expand_struct(
attrs: ContainerAttributes,
ident: &Ident,
s: &syn::DataStruct,
) -> Result<(Vec<syn::WherePredicate>, TokenStream)> { let s = Expansion {
attr: &attrs,
fields: &s.fields,
ident,
}; let bounds = s.generate_bounds()?; let body = s.generate_body()?;
let vars = s.fields.iter().enumerate().map(|(i, f)| { let var = f.ident.clone().unwrap_or_else(|| format_ident!("_{i}")); let member = f
.ident
.clone()
.map_or_else(|| syn::Member::Unnamed(i.into()), syn::Member::Named);
quote! { let#var = &self.#member; }
});
let body = quote! { #(#vars )* #body
};
Ok((bounds, body))
}
/// Expands a [`fmt::Debug`] derive macro for the provided enum. /// /// [`fmt::Debug`]: std::fmt::Debug fn expand_enum(
attrs: ContainerAttributes,
e: &syn::DataEnum,
) -> Result<(Vec<syn::WherePredicate>, TokenStream)> { let (bounds, match_arms) = e.variants.iter().try_fold(
(Vec::new(), TokenStream::new()),
|(mut bounds, mut arms), variant| { let ident = &variant.ident;
let v = Expansion {
attr: &attrs,
fields: &variant.fields,
ident,
}; let arm_body = v.generate_body()?;
bounds.extend(v.generate_bounds()?);
if input.peek(syn::LitStr) {
input.parse().map(Self::Fmt)
} else { let _ = input.parse::<syn::Path>().and_then(|p| { if ["skip", "ignore"].into_iter().any(|i| p.is_ident(i)) {
Ok(p)
} else {
Err(Error::new(
p.span(), "unknown attribute, expected `skip` or `ignore`",
))
}
})?;
Ok(Self::Skip)
}
}
}
/// Helper struct to generate [`Debug::fmt()`] implementation body and trait /// bounds for a struct or an enum variant. /// /// [`Debug::fmt()`]: std::fmt::Debug::fmt() #[derive(Debug)] struct Expansion<'a> {
attr: &'a ContainerAttributes,
/// Struct or enum [`Ident`](struct@Ident).
ident: &'a Ident,
/// Struct or enum [`syn::Fields`].
fields: &'a syn::Fields,
}
impl<'a> Expansion<'a> { /// Generates [`Debug::fmt()`] implementation for a struct or an enum variant. /// /// [`Debug::fmt()`]: std::fmt::Debug::fmt() fn generate_body(&self) -> Result<TokenStream> { matchself.fields {
syn::Fields::Unit => { let ident = self.ident.to_string();
Ok(quote! {
::core::fmt::Formatter::write_str(
__derive_more_f, #ident,
)
})
}
syn::Fields::Unnamed(unnamed) => { letmut exhaustive = true; let ident_str = self.ident.to_string();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.