use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, ToTokens as _, TokenStreamExt as _}; use syn::{
parse::{discouraged::Speculative as _, Parse, ParseStream},
parse_quote,
punctuated::Punctuated,
spanned::Spanned as _,
token, Ident,
};
/// Parses a [`VariantAttribute`] from the single provided [`syn::Attribute`]. fn parse_attr(attr: &syn::Attribute, fields: &syn::Fields) -> syn::Result<Self> { if matches!(attr.meta, syn::Meta::Path(_)) { return Ok(Self::From);
}
attr.parse_args_with(|input: ParseStream<'_>| { let ahead = input.fork(); match ahead.parse::<syn::Path>() {
Ok(p) if p.is_ident("forward") => {
input.advance_to(&ahead);
Ok(Self::Forward)
}
Ok(p) if p.is_ident("skip") || p.is_ident("ignore") => {
input.advance_to(&ahead);
Ok(Self::Skip)
}
Ok(p) if p.is_ident("types") => {
legacy_error(&ahead, input.span(), fields)
}
_ => input
.parse_terminated(Type::parse, token::Comma)
.map(Self::Types),
}
})
}
}
impl From<StructAttribute> for VariantAttribute { fn from(value: StructAttribute) -> Self { match value {
StructAttribute::Types(tys) => Self::Types(tys),
StructAttribute::Forward => Self::Forward,
}
}
}
/// Expansion of a macro for generating [`From`] implementation of a struct or /// enum. struct Expansion<'a> { /// [`From`] attributes. /// /// As a [`VariantAttribute`] is superset of a [`StructAttribute`], we use /// it for both derives.
attrs: Option<&'a VariantAttribute>,
/// Struct or enum [`Ident`].
ident: &'a Ident,
/// Variant [`Ident`] in case of enum expansion.
variant: Option<&'a Ident>,
/// Struct or variant [`syn::Fields`].
fields: &'a syn::Fields,
/// Struct or enum [`syn::Generics`].
generics: &'a syn::Generics,
/// Indicator whether one of the enum variants has /// [`VariantAttribute::From`], [`VariantAttribute::Types`] or /// [`VariantAttribute::Forward`]. /// /// Always [`false`] for structs.
has_explicit_from: bool,
}
impl<'a> Expansion<'a> { /// Expands [`From`] implementations for a struct or an enum variant. fn expand(&self) -> syn::Result<TokenStream> { usecrate::utils::FieldsExt as _;
let ident = self.ident; let field_tys = self.fields.iter().map(|f| &f.ty).collect::<Vec<_>>(); let (impl_gens, ty_gens, where_clause) = self.generics.split_for_impl();
let skip_variant = self.has_explicit_from
|| (self.variant.is_some() && self.fields.is_empty()); match (self.attrs, skip_variant) {
(Some(VariantAttribute::Types(tys)), _) => {
tys.iter().map(|ty| { let variant = self.variant.iter();
letmut from_tys = self.fields.validate_type(ty)?; let init = self.expand_fields(|ident, ty, index| { let ident = ident.into_iter(); let index = index.into_iter(); let from_ty = from_tys.next().unwrap_or_else(|| unreachable!());
quote! { #(#ident: )* <#tyas ::core::convert::From<#from_ty>>::from(
value #( .#index )*
),
}
});
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.