use proc_macro2::{Span, TokenStream}; use quote::{quote, ToTokens as _}; use syn::{
ext::IdentExt as _,
parse::{discouraged::Speculative as _, Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned as _,
token, Ident,
};
usecrate::{
parsing::Type,
utils::{polyfill, Either, FieldsExt as _},
};
/// Expands an [`Into`] derive macro. pubfn expand(input: &syn::DeriveInput, _: &'static str) -> syn::Result<TokenStream> { 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",
)),
}?;
let attr = StructAttribute::parse_attrs(&input.attrs, &data.fields)?
.unwrap_or_else(|| StructAttribute {
owned: Some(Punctuated::new()),
r#ref: None,
ref_mut: None,
}); let ident = &input.ident; let fields = data
.fields
.iter()
.enumerate()
.filter_map(|(i, f)| match SkipFieldAttribute::parse_attrs(&f.attrs) {
Ok(None) => Some(Ok((
&f.ty,
f.ident
.as_ref()
.map_or_else(|| Either::Right(syn::Index::from(i)), Either::Left),
))),
Ok(Some(_)) => None,
Err(e) => Some(Err(e)),
})
.collect::<syn::Result<Vec<_>>>()?; let (fields_tys, fields_idents): (Vec<_>, Vec<_>) = fields.into_iter().unzip(); let (fields_tys, fields_idents) = (&fields_tys, &fields_idents);
let expand = |tys: Option<Punctuated<_, _>>, r: bool, m: bool| { let Some(tys) = tys else { return Either::Left(iter::empty());
};
let lf =
r.then(|| syn::Lifetime::new("'__derive_more_into", Span::call_site())); let r = r.then(token::And::default); let m = m.then(token::Mut::default);
let Ok(metas) = tokens.parse_terminated(polyfill::Meta::parse, token::Comma) else { return Ok(());
};
let parse_list = |list: polyfill::MetaList, attrs: &mut Option<Vec<_>>| { if !list.path.is_ident("types") { return None;
} for meta in list
.parse_args_with(Punctuated::<_, token::Comma>::parse_terminated)
.ok()?
{
attrs.get_or_insert_with(Vec::new).push(match meta {
polyfill::NestedMeta::Lit(syn::Lit::Str(str)) => str.value(),
polyfill::NestedMeta::Meta(polyfill::Meta::Path(path)) => {
path.into_token_stream().to_string()
}
_ => return None,
})
}
Some(())
};
let Some((top_level, owned, ref_, ref_mut)) = metas
.into_iter()
.try_fold(
(None, None, None, None),
|(mut top_level, mut owned, mut ref_, mut ref_mut), meta| { let is = |name| {
matches!(&meta, polyfill::Meta::Path(p) if p.is_ident(name))
|| matches!(&meta, polyfill::Meta::List(list) if list.path.is_ident(name))
}; let parse_inner = |meta, attrs: &mut Option<_>| { match meta {
polyfill::Meta::Path(_) => { let _ = attrs.get_or_insert_with(Vec::new);
Some(())
}
polyfill::Meta::List(list) => { iflet polyfill::NestedMeta::Meta(polyfill::Meta::List(list)) = list
.parse_args_with(Punctuated::<_, token::Comma>::parse_terminated)
.ok()?
.pop()?
.into_value()
{
parse_list(list, attrs)
} else {
None
}
}
}
};
match meta {
meta if is("owned") => parse_inner(meta, &mut owned),
meta if is("ref") => parse_inner(meta, &mut ref_),
meta if is("ref_mut") => parse_inner(meta, &mut ref_mut),
polyfill::Meta::List(list) => parse_list(list, &mut top_level),
_ => None,
}
.map(|_| (top_level, owned, ref_, ref_mut))
},
)
.filter(|(top_level, owned, ref_, ref_mut)| {
[top_level, owned, ref_, ref_mut]
.into_iter()
.any(|l| l.as_ref().map_or(false, |l| !l.is_empty()))
}) else { return Ok(());
};
if [&owned, &ref_, &ref_mut].into_iter().any(Option::is_some) { let format = |list: Option<Vec<_>>, name: &str| match list {
Some(l) if top_level.as_ref().map_or(true, Vec::is_empty) && l.is_empty() =>
{
Some(name.to_owned())
}
Some(l) => Some(format!( "{}({})",
name,
l.into_iter()
.chain(top_level.clone().into_iter().flatten())
.map(map_ty)
.chain(field.clone())
.collect::<Vec<_>>()
.join(", "),
)),
None => None,
}; let format = [
format(owned, "owned"),
format(ref_, "ref"),
format(ref_mut, "ref_mut"),
]
.into_iter()
.flatten()
.collect::<Vec<_>>()
.join(", ");
Err(syn::Error::new(
span,
format!("legacy syntax, use `{format}` instead"),
))
} else {
Err(syn::Error::new(
span,
format!( "legacy syntax, remove `types` and use `{}` instead",
top_level.unwrap_or_else(|| unreachable!()).join(", "),
),
))
}
}
Messung V0.5 in Prozent
¤ 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.0.11Bemerkung:
(vorverarbeitet am 2026-06-18)
¤
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.