let attrs = ContainerAttributes::parse_attrs(&input.attrs, &attr_name)?
.map(Spanning::into_inner)
.unwrap_or_default(); let ident = &input.ident;
let type_params = input
.generics
.params
.iter()
.filter_map(|p| match p {
syn::GenericParam::Type(t) => Some(&t.ident),
syn::GenericParam::Const(..) | syn::GenericParam::Lifetime(..) => None,
})
.collect::<Vec<_>>();
let (bounds, body) = match &input.data {
syn::Data::Struct(s) => {
expand_struct(attrs, ident, s, &type_params, &attr_name)
}
syn::Data::Enum(e) => expand_enum(attrs, e, &type_params, &attr_name),
syn::Data::Union(_) => { return Err(syn::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)
};
Ok(quote! { #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types #[automatically_derived] impl#impl_gens derive_more::core::fmt::Debug for #ident#ty_gens#where_clause { #[inline]
fn fmt(
&self, __derive_more_f: &mut derive_more::core::fmt::Formatter<'_>
) -> derive_more::core::fmt::Result { #body
}
}
})
}
/// Expands a [`fmt::Debug`] derive macro for the provided struct. /// /// [`fmt::Debug`]: std::fmt::Debug
fn expand_struct(
attrs: ContainerAttributes,
ident: &syn::Ident,
s: &syn::DataStruct,
type_params: &[&syn::Ident],
attr_name: &syn::Ident,
) -> syn::Result<(Vec<syn::WherePredicate>, TokenStream)> { let s = Expansion {
attr: &attrs,
fields: &s.fields,
type_params,
ident,
attr_name,
};
s.validate_attrs()?; 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( mut attrs: ContainerAttributes,
e: &syn::DataEnum,
type_params: &[&syn::Ident],
attr_name: &syn::Ident,
) -> syn::Result<(Vec<syn::WherePredicate>, TokenStream)> { iflet Some(enum_fmt) = attrs.fmt.as_ref() { return Err(syn::Error::new_spanned(
enum_fmt,
format!( "`#[{attr_name}(\"...\", ...)]` attribute is not allowed on enum, place it on its \
variants instead",
),
));
}
let (bounds, match_arms) = e.variants.iter().try_fold(
(Vec::new(), TokenStream::new()),
|(mut bounds, mut arms), variant| { let ident = &variant.ident;
let body = match_arms
.is_empty()
.then(|| quote! { match *self {} })
.unwrap_or_else(|| quote! { matchself { #match_arms } });
Ok((bounds, body))
}
/// Representation of a [`fmt::Debug`] derive macro field attribute. /// /// ```rust,ignore /// #[debug(skip)] /// #[debug("<fmt-literal>", <fmt-args>)] /// ``` /// /// [`fmt::Debug`]: std::fmt::Debug type FieldAttribute = Either<attr::Skip, FmtAttribute>;
/// 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@syn::Ident).
ident: &'a syn::Ident,
/// Struct or enum [`syn::Fields`].
fields: &'a syn::Fields,
/// Type parameters in this struct or enum.
type_params: &'a [&'a syn::Ident],
/// Name of the attributes, considered by this macro.
attr_name: &'a syn::Ident,
}
impl Expansion<'_> { /// Validates attributes of this [`Expansion`] to be consistent.
fn validate_attrs(&self) -> syn::Result<()> { ifself.attr.fmt.is_some() {
for field_attr in self
.fields
.iter()
.map(|f| FieldAttribute::parse_attrs(&f.attrs, self.attr_name))
{ iflet Some(FieldAttribute::Right(fmt_attr)) =
field_attr?.map(Spanning::into_inner)
{ return Err(syn::Error::new_spanned(
fmt_attr, "`#[debug(...)]` attributes are not allowed on fields when \
`#[debug(\"...\", ...)]` is specified on struct or variant",
));
}
}
}
Ok(())
}
/// Generates [`Debug::fmt()`] implementation for a struct or an enum variant. /// /// [`Debug::fmt()`]: std::fmt::Debug::fmt()
fn generate_body(&self) -> syn::Result<TokenStream> { iflet Some(fmt) = &self.attr.fmt { return Ok( iflet Some((expr, trait_ident)) =
fmt.transparent_call_on_fields(self.fields)
{
quote! { derive_more::core::fmt::#trait_ident::fmt(#expr, __derive_more_f) }
} else { let deref_args = fmt.additional_deref_args(self.fields);
/// Generates trait bounds for a struct or an enum variant.
fn generate_bounds(&self) -> syn::Result<Vec<syn::WherePredicate>> { letmut out = self.attr.bounds.0.clone().into_iter().collect::<Vec<_>>();
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.