use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, ToTokens as _, TokenStreamExt as _}; use syn::{
parse::{Parse, ParseStream},
parse_quote,
spanned::Spanned as _,
token,
};
usecrate::utils::{
attr::{self, ParseMultiple as _},
polyfill, Either, Spanning,
};
/// Expands a [`From`] derive macro. pubfn expand(input: &syn::DeriveInput, _: &'static str) -> syn::Result<TokenStream> { let attr_name = format_ident!("from");
/// Representation of a [`From`] derive macro struct container attribute. /// /// ```rust,ignore /// #[from(forward)] /// #[from(<types>)] /// ``` type StructAttribute = attr::Conversion;
/// Representation of a [`From`] derive macro enum variant attribute. /// /// ```rust,ignore /// #[from] /// #[from(skip)] #[from(ignore)] /// #[from(forward)] /// #[from(<types>)] /// ``` type VariantAttribute = attr::FieldConversion;
/// 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>,
/// Variant [`syn::Ident`] in case of enum expansion. /// /// [`syn::Ident`]: struct@syn::Ident
variant: Option<&'a syn::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::Empty`], [`VariantAttribute::Types`] or /// [`VariantAttribute::Forward`]. /// /// Always [`false`] for structs.
has_explicit_from: bool,
}
impl Expansion<'_> { /// 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.0.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 derive_more::core::convert::From<#from_ty>>::from(
value #( .#index )*
),
}
});
Ok(quote! { #[allow(unreachable_code)] // omit warnings for `!` and unreachable types #[automatically_derived] impl#impl_gens derive_more::core::convert::From<#ty> for#ident#ty_gens#where_clause { #[inline] fn from(value: #ty) -> Self { #ident#( :: #variant )* #init
}
}
})
})
.collect()
}
(Some(VariantAttribute::Empty(_)), _) | (None, false) => { let variant = self.variant.iter(); let init = self.expand_fields(|ident, _, index| { let ident = ident.into_iter(); let index = index.into_iter();
quote! { #(#ident: )* value #( . #index )*, }
});
Ok(quote! { #[allow(unreachable_code)] // omit warnings for `!` and other unreachable types #[automatically_derived] impl#impl_gens derive_more::core::convert::From<(#(#field_tys ),*)> for#ident#ty_gens#where_clause { #[inline] fn from(value: (#(#field_tys ),*)) -> Self { #ident#( :: #variant )* #init
}
}
})
}
(Some(VariantAttribute::Forward(_)), _) => { letmut i = 0; letmut gen_idents = Vec::with_capacity(self.fields.len()); let init = self.expand_fields(|ident, ty, index| { let ident = ident.into_iter(); let index = index.into_iter(); let gen_ident = format_ident!("__FromT{i}"); let out = quote! { #(#ident: )* <#tyas derive_more::core::convert::From<#gen_ident>>::from(
value #( .#index )*
),
};
gen_idents.push(gen_ident);
i += 1;
out
});
let variant = self.variant.iter(); let generics = { letmut generics = self.generics.clone(); for (ty, ident) in field_tys.iter().zip(&gen_idents) {
generics
.make_where_clause()
.predicates
.push(parse_quote! { #ty: derive_more::core::convert::From<#ident> });
generics
.params
.push(syn::TypeParam::from(ident.clone()).into());
}
generics
}; let (impl_gens, _, where_clause) = generics.split_for_impl();
/// [`attr::Parser`] considering legacy syntax for [`attr::Types`] and emitting [`legacy_error`], if /// any occurs. struct ConsiderLegacySyntax<'a> { /// [`syn::Fields`] of a struct or enum variant, the attribute is parsed for.
fields: &'a syn::Fields,
}
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.