use std::{
any::{Any, TypeId},
borrow::Cow,
iter, slice,
};
use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, ToTokens as _}; use syn::{
ext::IdentExt as _,
parse::{discouraged::Speculative as _, Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned as _,
token,
};
usecrate::utils::{
attr::{self, ParseMultiple as _},
polyfill, Either, FieldsExt, Spanning,
};
/// Expands an [`Into`] derive macro. pubfn expand(input: &syn::DeriveInput, _: &'static str) -> syn::Result<TokenStream> { let attr_name = format_ident!("into");
let data = match &input.data {
syn::Data::Struct(data) => Ok(data),
syn::Data::Enum(e) => Err(syn::Error::new(
e.enum_token.span(), "`Into` cannot be derived for enums",
)),
syn::Data::Union(u) => Err(syn::Error::new(
u.union_token.span(), "`Into` cannot be derived for unions",
)),
}?;
/// Expansion of an [`Into`] derive macro, generating [`From`] implementations for a struct. struct Expansion<'a> { /// [`syn::Ident`] of the struct. /// /// [`syn::Ident`]: struct@syn::Ident
input_ident: &'a syn::Ident,
/// [`syn::Generics`] of the struct.
input_generics: &'a syn::Generics,
/// Fields to convert from, along with their indices.
fields: Vec<(usize, &'a syn::Field)>,
/// Conversions to be generated.
convs: ConversionsAttribute,
}
/// [`Into`] conversions specified by a [`ConversionsAttribute`]. #[derive(Clone, Debug, Default)] struct Conversions { /// Indicator whether these [`Conversions`] should contain a conversion into fields type.
consider_fields_ty: bool,
/// [`syn::Type`]s explicitly specified in a [`ConversionsAttribute`].
tys: Punctuated<syn::Type, token::Comma>,
}
/// Representation of an [`Into`] derive macro attribute describing specified [`Into`] conversions. /// /// ```rust,ignore /// #[into(<types>)] /// #[into(owned(<types>), ref(<types>), ref_mut(<types>))] /// ``` #[derive(Clone, Debug)] struct ConversionsAttribute { /// [`syn::Type`]s wrapped into `owned(...)` or simply `#[into(...)]`.
owned: Conversions,
/// [`syn::Type`]s wrapped into `ref(...)`.
r#ref: Conversions,
/// [`syn::Type`]s wrapped into `ref_mut(...)`.
ref_mut: Conversions,
}
while !input.is_empty() { let ahead = input.fork(); let res = if ahead.peek(syn::Ident::peek_any) {
ahead.call(syn::Ident::parse_any).map(Into::into)
} else {
ahead.parse::<syn::Path>()
}; match res {
Ok(p) if p.is_ident("owned") => {
has_wrapped_type = true;
parse_inner(ahead, &mut out.owned)?;
}
Ok(p) if p.is_ident("ref") => {
has_wrapped_type = true;
parse_inner(ahead, &mut out.r#ref)?;
}
Ok(p) if p.is_ident("ref_mut") => {
has_wrapped_type = true;
parse_inner(ahead, &mut out.ref_mut)?;
}
_ => { let ty = input.parse::<syn::Type>()?; let _ = top_level_type.get_or_insert_with(|| ty.clone());
out.owned.tys.push_value(ty);
if input.peek(token::Comma) {
out.owned.tys.push_punct(input.parse::<token::Comma>()?)
}
}
}
}
iflet Some(ty) = top_level_type.filter(|_| has_wrapped_type) {
Err(syn::Error::new(
ty.span(),
format!( "mixing regular types with wrapped into `owned`/`ref`/`ref_mut` is not \
allowed, try wrapping this type into `owned({ty}), ref({ty}), ref_mut({ty})`",
ty = ty.into_token_stream(),
),
))
} else {
Ok(out)
}
}
}
/// [`attr::Parser`] considering legacy syntax and performing [`check_legacy_syntax()`] for a /// [`StructAttribute`] or a [`FieldAttribute`]. struct ConsiderLegacySyntax<F> { /// [`syn::Field`]s the [`StructAttribute`] or [`FieldAttribute`] is parsed for.
fields: F,
}
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.