From 4f18d0413c66cdea423f8689dea8b2f8a67f3c56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 18:22:58 +0000 Subject: [PATCH] deps: bump syn from 1.0.109 to 2.0.2 Pull-Request: #3645. --- Cargo.lock | 2 +- swarm-derive/Cargo.toml | 2 +- swarm-derive/src/lib.rs | 134 ++++++++++++++++++++++++------------ swarm/tests/swarm_derive.rs | 21 ++++++ 4 files changed, 114 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67847ae9..fb2a020a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2785,7 +2785,7 @@ version = "0.32.0" dependencies = [ "heck", "quote", - "syn 1.0.109", + "syn 2.0.2", ] [[package]] diff --git a/swarm-derive/Cargo.toml b/swarm-derive/Cargo.toml index 7b7bfcf3..7e934fc8 100644 --- a/swarm-derive/Cargo.toml +++ b/swarm-derive/Cargo.toml @@ -16,7 +16,7 @@ proc-macro = true [dependencies] heck = "0.4" quote = "1.0" -syn = { version = "1.0.109", default-features = false, features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"] } +syn = { version = "2.0.2", default-features = false, features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"] } # Passing arguments to the docsrs builder in order to properly document cfg's. # More information: https://docs.rs/about/builds#cross-compiling diff --git a/swarm-derive/src/lib.rs b/swarm-derive/src/lib.rs index 2ebc4aec..d4e52bab 100644 --- a/swarm-derive/src/lib.rs +++ b/swarm-derive/src/lib.rs @@ -24,8 +24,11 @@ use heck::ToUpperCamelCase; use proc_macro::TokenStream; use quote::quote; -use syn::parse::Parse; -use syn::{parse_macro_input, Data, DataStruct, DeriveInput}; +use syn::punctuated::Punctuated; +use syn::{ + parse_macro_input, Data, DataStruct, DeriveInput, Expr, ExprLit, Lit, Meta, MetaNameValue, + Token, +}; /// Generates a delegating `NetworkBehaviour` implementation for the struct this is used for. See /// the trait documentation for better description. @@ -48,8 +51,13 @@ fn build(ast: &DeriveInput) -> TokenStream { fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { let name = &ast.ident; let (_, ty_generics, where_clause) = ast.generics.split_for_impl(); - let prelude_path = parse_attribute_value_by_key::(ast, "prelude") - .unwrap_or_else(|| syn::parse_quote! { ::libp2p::swarm::derive_prelude }); + let BehaviourAttributes { + prelude_path, + user_specified_out_event, + } = match parse_attributes(ast) { + Ok(attrs) => attrs, + Err(e) => return e, + }; let multiaddr = quote! { #prelude_path::Multiaddr }; let trait_to_impl = quote! { #prelude_path::NetworkBehaviour }; @@ -91,10 +99,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // If we find a `#[behaviour(out_event = "Foo")]` attribute on the // struct, we set `Foo` as the out event. If not, the `OutEvent` is // generated. - let user_provided_out_event_name = - parse_attribute_value_by_key::(ast, "out_event"); - - match user_provided_out_event_name { + match user_specified_out_event { // User provided `OutEvent`. Some(name) => { let definition = None; @@ -111,7 +116,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { // User did not provide `OutEvent`. Generate it. None => { let enum_name_str = ast.ident.to_string() + "Event"; - let enum_name: syn::Type = syn::parse_str(&enum_name_str).unwrap(); + let enum_name: syn::Type = + syn::parse_str(&enum_name_str).expect("ident + `Event` is a valid type"); let definition = { let fields = data_struct.fields.iter().map(|field| { let variant: syn::Variant = syn::parse_str( @@ -122,7 +128,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { .to_string() .to_upper_camel_case(), ) - .unwrap(); + .expect("uppercased field name to be a valid enum variant"); let ty = &field.ty; (variant, ty) }); @@ -680,7 +686,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { &field .to_string() .to_upper_camel_case() - ).unwrap(); + ).expect("uppercased field name to be a valid enum variant name"); quote! { #out_event_name::#event_variant(event) } } else { quote! { event.into() } @@ -842,41 +848,83 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream { final_quote.into() } -/// Parses the `value` of a key=value pair in the `#[behaviour]` attribute into the requested type. -/// -/// Only `String` values are supported, e.g. `#[behaviour(foo="bar")]`. -fn parse_attribute_value_by_key(ast: &DeriveInput, key: &str) -> Option -where - T: Parse, -{ - ast.attrs - .iter() - .filter_map(get_meta_items) - .flatten() - .filter_map(|meta_item| { - if let syn::NestedMeta::Meta(syn::Meta::NameValue(ref m)) = meta_item { - if m.path.is_ident(key) { - if let syn::Lit::Str(ref s) = m.lit { - return Some(syn::parse_str(&s.value()).unwrap()); - } - } - } - None - }) - .next() +struct BehaviourAttributes { + prelude_path: syn::Path, + user_specified_out_event: Option, } -fn get_meta_items(attr: &syn::Attribute) -> Option> { - if attr.path.segments.len() == 1 && attr.path.segments[0].ident == "behaviour" { - match attr.parse_meta() { - Ok(syn::Meta::List(ref meta)) => Some(meta.nested.iter().cloned().collect()), - Ok(_) => None, - Err(e) => { - eprintln!("error parsing attribute metadata: {e}"); - None +/// Parses the `value` of a key=value pair in the `#[behaviour]` attribute into the requested type. +fn parse_attributes(ast: &DeriveInput) -> Result { + let mut attributes = BehaviourAttributes { + prelude_path: syn::parse_quote! { ::libp2p::swarm::derive_prelude }, + user_specified_out_event: None, + }; + + for attr in ast + .attrs + .iter() + .filter(|attr| attr.path().is_ident("behaviour")) + { + let nested = attr + .parse_args_with(Punctuated::::parse_terminated) + .expect("`parse_args_with` never fails when parsing nested meta"); + + for meta in nested { + if meta.path().is_ident("prelude") { + match meta { + Meta::Path(_) => unimplemented!(), + Meta::List(_) => unimplemented!(), + Meta::NameValue(MetaNameValue { + value: + Expr::Lit(ExprLit { + lit: Lit::Str(s), .. + }), + .. + }) => { + attributes.prelude_path = syn::parse_str(&s.value()).unwrap(); + } + Meta::NameValue(name_value) => { + return Err(syn::Error::new_spanned( + name_value.value, + "`prelude` value must be a quoted path", + ) + .to_compile_error() + .into()); + } + } + + continue; + } + + if meta.path().is_ident("out_event") { + match meta { + Meta::Path(_) => unimplemented!(), + Meta::List(_) => unimplemented!(), + + Meta::NameValue(MetaNameValue { + value: + Expr::Lit(ExprLit { + lit: Lit::Str(s), .. + }), + .. + }) => { + attributes.user_specified_out_event = + Some(syn::parse_str(&s.value()).unwrap()); + } + Meta::NameValue(name_value) => { + return Err(syn::Error::new_spanned( + name_value.value, + "`out_event` value must be a quoted type", + ) + .to_compile_error() + .into()); + } + } + + continue; } } - } else { - None } + + Ok(attributes) } diff --git a/swarm/tests/swarm_derive.rs b/swarm/tests/swarm_derive.rs index e7e2e471..c35101b7 100644 --- a/swarm/tests/swarm_derive.rs +++ b/swarm/tests/swarm_derive.rs @@ -433,6 +433,27 @@ fn generated_out_event_derive_debug() { require_debug::(); } +#[test] +fn multiple_behaviour_attributes() { + #[allow(dead_code)] + #[derive(NetworkBehaviour)] + #[behaviour(out_event = "FooEvent")] + #[behaviour(prelude = "libp2p_swarm::derive_prelude")] + struct Foo { + ping: ping::Behaviour, + } + + require_net_behaviour::(); + + struct FooEvent; + + impl From for FooEvent { + fn from(_: ping::Event) -> Self { + unimplemented!() + } + } +} + #[test] fn custom_out_event_no_type_parameters() { use libp2p_identity::PeerId;