Skip to content

Commit

Permalink
Corrections
Browse files Browse the repository at this point in the history
  • Loading branch information
ilslv committed Jul 14, 2023
1 parent 2db2f97 commit 5d77999
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 49 deletions.
76 changes: 34 additions & 42 deletions impl/src/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens as _};
use syn::{
ext::IdentExt as _,
parse::{discouraged::Speculative as _, Parse, ParseStream, Parser},
parse::{discouraged::Speculative as _, Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned as _,
token, Error, Ident, Result,
};

use crate::utils::polyfill;
use crate::{
parsing::Type,
utils::{validate_tuple, Either, EitherExt as _},
Expand Down Expand Up @@ -68,7 +69,7 @@ pub fn expand(input: &syn::DeriveInput, _: &'static str) -> Result<TokenStream>

let gens = if let Some(lf) = lf.clone() {
let mut gens = input.generics.clone();
gens.params.push(syn::LifetimeDef::new(lf).into());
gens.params.push(syn::LifetimeParam::new(lf).into());
Cow::Owned(gens)
} else {
Cow::Borrowed(&input.generics)
Expand Down Expand Up @@ -148,7 +149,7 @@ impl StructAttribute {
attrs
.as_ref()
.iter()
.filter(|attr| attr.path.is_ident("into"))
.filter(|attr| attr.path().is_ident("into"))
.try_fold(None, |mut attrs, attr| {
let merge = |out: &mut Option<_>, tys| match (out.as_mut(), tys) {
(None, Some(tys)) => {
Expand All @@ -158,10 +159,8 @@ impl StructAttribute {
(Some(_), None) | (None, None) => {}
};

let field_attr = Parser::parse2(
infer(|stream| Self::parse(stream, fields)),
attr.tokens.clone(),
)?;
let field_attr =
attr.parse_args_with(infer(|stream| Self::parse(stream, fields)))?;
let out = attrs.get_or_insert_with(Self::default);
merge(&mut out.owned, field_attr.owned);
merge(&mut out.r#ref, field_attr.r#ref);
Expand All @@ -172,15 +171,8 @@ impl StructAttribute {
}

/// Parses single [`StructAttribute`].
fn parse(input: ParseStream<'_>, fields: &syn::Fields) -> Result<Self> {
use proc_macro2::Delimiter::Parenthesis;

let error_span = input.cursor().group(Parenthesis).map(|(_, span, _)| span);
let content;
syn::parenthesized!(content in input);
let error_span = error_span.unwrap_or_else(|| unreachable!());

check_legacy_syntax(&content, error_span, fields)?;
fn parse(content: ParseStream<'_>, fields: &syn::Fields) -> Result<Self> {
check_legacy_syntax(&content, fields)?;

let mut out = Self::default();

Expand All @@ -194,7 +186,7 @@ impl StructAttribute {

types.extend(
inner
.parse_terminated::<_, token::Comma>(Type::parse)?
.parse_terminated(Type::parse, token::Comma)?
.into_pairs(),
);
}
Expand Down Expand Up @@ -270,11 +262,10 @@ impl SkipFieldAttribute {
Ok(attrs
.as_ref()
.iter()
.filter(|attr| attr.path.is_ident("into"))
.filter(|attr| attr.path().is_ident("into"))
.try_fold(None, |mut attrs, attr| {
let field_attr =
syn::parse2::<SkipFieldAttribute>(attr.tokens.clone())?;
if let Some((path, _)) = attrs.replace((&attr.path, field_attr)) {
let field_attr = attr.parse_args::<SkipFieldAttribute>()?;
if let Some((path, _)) = attrs.replace((attr.path(), field_attr)) {
Err(Error::new(
path.span(),
"only single `#[into(...)]` attribute is allowed here",
Expand All @@ -288,10 +279,7 @@ impl SkipFieldAttribute {
}

impl Parse for SkipFieldAttribute {
fn parse(input: ParseStream) -> Result<Self> {
let content;
syn::parenthesized!(content in input);

fn parse(content: ParseStream) -> Result<Self> {
match content.parse::<syn::Path>()? {
p if p.is_ident("skip") | p.is_ident("ignore") => Ok(Self),
p => Err(Error::new(
Expand All @@ -303,11 +291,8 @@ impl Parse for SkipFieldAttribute {
}

/// [`Error`]ors for legacy syntax: `#[into(types(i32, "&str"))]`.
fn check_legacy_syntax(
tokens: ParseStream<'_>,
span: Span,
fields: &syn::Fields,
) -> Result<()> {
fn check_legacy_syntax(tokens: ParseStream<'_>, fields: &syn::Fields) -> Result<()> {
let span = tokens.span();
let tokens = tokens.fork();

let map_ty = |s: String| {
Expand Down Expand Up @@ -344,18 +329,21 @@ fn check_legacy_syntax(
)),
};

let Ok(metas) = tokens.parse_terminated::<_, token::Comma>(syn::Meta::parse) else {
let Ok(metas) = tokens.parse_terminated(polyfill::Meta::parse, token::Comma) else {
return Ok(());
};

let parse_list = |list: syn::MetaList, attrs: &mut Option<Vec<_>>| {
let parse_list = |list: polyfill::MetaList, attrs: &mut Option<Vec<_>>| {
if !list.path.is_ident("types") {
return None;
}
for meta in list.nested {
for meta in list
.parse_args_with(Punctuated::<_, token::Comma>::parse_terminated)
.ok()?
{
attrs.get_or_insert_with(Vec::new).push(match meta {
syn::NestedMeta::Lit(syn::Lit::Str(str)) => str.value(),
syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
polyfill::NestedMeta::Lit(syn::Lit::Str(str)) => str.value(),
polyfill::NestedMeta::Meta(polyfill::Meta::Path(path)) => {
path.into_token_stream().to_string()
}
_ => return None,
Expand All @@ -370,31 +358,35 @@ fn check_legacy_syntax(
(None, None, None, None),
|(mut top_level, mut owned, mut ref_, mut ref_mut), meta| {
let is = |name| {
matches!(&meta, syn::Meta::Path(p) if p.is_ident(name))
|| matches!(&meta, syn::Meta::List(list) if list.path.is_ident(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 {
syn::Meta::Path(_) => {
polyfill::Meta::Path(_) => {
let _ = attrs.get_or_insert_with(Vec::new);
Some(())
}
syn::Meta::List(mut list) => {
if let syn::NestedMeta::Meta(syn::Meta::List(list)) = list.nested.pop()?.into_value() {
polyfill::Meta::List(list) => {
if let 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
}
}
_ => 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),
syn::Meta::List(list) => parse_list(list, &mut top_level),
polyfill::Meta::List(list) => parse_list(list, &mut top_level),
_ => None,
}
.map(|_| (top_level, owned, ref_, ref_mut))
Expand Down
6 changes: 3 additions & 3 deletions impl/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ pub(crate) mod polyfill {
}

impl PathOrKeyword {
pub(super) fn is_ident<I: ?Sized>(&self, ident: &I) -> bool
pub(crate) fn is_ident<I: ?Sized>(&self, ident: &I) -> bool
where
syn::Ident: PartialEq<I>,
{
Expand Down Expand Up @@ -1177,8 +1177,8 @@ pub(crate) mod polyfill {

#[derive(Clone)]
pub(crate) struct MetaList {
pub(super) path: PathOrKeyword,
pub(super) tokens: TokenStream,
pub(crate) path: PathOrKeyword,
pub(crate) tokens: TokenStream,
}

impl Parse for MetaList {
Expand Down
4 changes: 2 additions & 2 deletions tests/compile_fail/into/legacy_complex_attribute.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: legacy syntax, use `owned(Cow<'_ str>, i32, &str, String), ref(i32, &str, String), ref_mut(i32, &str, String)` instead
--> tests/compile_fail/into/legacy_complex_attribute.rs:2:7
--> tests/compile_fail/into/legacy_complex_attribute.rs:2:8
|
2 | #[into(owned(types("Cow<'_ str>")), ref, ref_mut, types(i32, "&str"))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^
4 changes: 2 additions & 2 deletions tests/compile_fail/into/legacy_types_attribute.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: legacy syntax, remove `types` and use `i32, &str` instead
--> tests/compile_fail/into/legacy_types_attribute.rs:2:7
--> tests/compile_fail/into/legacy_types_attribute.rs:2:8
|
2 | #[into(types(i32, "&str"))]
| ^^^^^^^^^^^^^^^^^^^^
| ^^^^^
1 change: 1 addition & 0 deletions tests/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ extern crate alloc;
use alloc::{borrow::Cow, string::String};
#[cfg(feature = "std")]
use std::borrow::Cow;
use std::mem;

use derive_more::Into;
use static_assertions::assert_not_impl_any;
Expand Down

0 comments on commit 5d77999

Please sign in to comment.