Skip to content

Commit 4f18d04

Browse files
deps: bump syn from 1.0.109 to 2.0.2
Pull-Request: #3645.
1 parent 9f63a0a commit 4f18d04

File tree

4 files changed

+110
-41
lines changed

4 files changed

+110
-41
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

swarm-derive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ proc-macro = true
1616
[dependencies]
1717
heck = "0.4"
1818
quote = "1.0"
19-
syn = { version = "1.0.109", default-features = false, features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"] }
19+
syn = { version = "2.0.2", default-features = false, features = ["clone-impls", "derive", "parsing", "printing", "proc-macro"] }
2020

2121
# Passing arguments to the docsrs builder in order to properly document cfg's.
2222
# More information: https://docs.rs/about/builds#cross-compiling

swarm-derive/src/lib.rs

Lines changed: 87 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@
2424
use heck::ToUpperCamelCase;
2525
use proc_macro::TokenStream;
2626
use quote::quote;
27-
use syn::parse::Parse;
28-
use syn::{parse_macro_input, Data, DataStruct, DeriveInput};
27+
use syn::punctuated::Punctuated;
28+
use syn::{
29+
parse_macro_input, Data, DataStruct, DeriveInput, Expr, ExprLit, Lit, Meta, MetaNameValue,
30+
Token,
31+
};
2932

3033
/// Generates a delegating `NetworkBehaviour` implementation for the struct this is used for. See
3134
/// the trait documentation for better description.
@@ -48,8 +51,13 @@ fn build(ast: &DeriveInput) -> TokenStream {
4851
fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
4952
let name = &ast.ident;
5053
let (_, ty_generics, where_clause) = ast.generics.split_for_impl();
51-
let prelude_path = parse_attribute_value_by_key::<syn::Path>(ast, "prelude")
52-
.unwrap_or_else(|| syn::parse_quote! { ::libp2p::swarm::derive_prelude });
54+
let BehaviourAttributes {
55+
prelude_path,
56+
user_specified_out_event,
57+
} = match parse_attributes(ast) {
58+
Ok(attrs) => attrs,
59+
Err(e) => return e,
60+
};
5361

5462
let multiaddr = quote! { #prelude_path::Multiaddr };
5563
let trait_to_impl = quote! { #prelude_path::NetworkBehaviour };
@@ -91,10 +99,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
9199
// If we find a `#[behaviour(out_event = "Foo")]` attribute on the
92100
// struct, we set `Foo` as the out event. If not, the `OutEvent` is
93101
// generated.
94-
let user_provided_out_event_name =
95-
parse_attribute_value_by_key::<syn::Type>(ast, "out_event");
96-
97-
match user_provided_out_event_name {
102+
match user_specified_out_event {
98103
// User provided `OutEvent`.
99104
Some(name) => {
100105
let definition = None;
@@ -111,7 +116,8 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
111116
// User did not provide `OutEvent`. Generate it.
112117
None => {
113118
let enum_name_str = ast.ident.to_string() + "Event";
114-
let enum_name: syn::Type = syn::parse_str(&enum_name_str).unwrap();
119+
let enum_name: syn::Type =
120+
syn::parse_str(&enum_name_str).expect("ident + `Event` is a valid type");
115121
let definition = {
116122
let fields = data_struct.fields.iter().map(|field| {
117123
let variant: syn::Variant = syn::parse_str(
@@ -122,7 +128,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
122128
.to_string()
123129
.to_upper_camel_case(),
124130
)
125-
.unwrap();
131+
.expect("uppercased field name to be a valid enum variant");
126132
let ty = &field.ty;
127133
(variant, ty)
128134
});
@@ -680,7 +686,7 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
680686
&field
681687
.to_string()
682688
.to_upper_camel_case()
683-
).unwrap();
689+
).expect("uppercased field name to be a valid enum variant name");
684690
quote! { #out_event_name::#event_variant(event) }
685691
} else {
686692
quote! { event.into() }
@@ -842,41 +848,83 @@ fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> TokenStream {
842848
final_quote.into()
843849
}
844850

851+
struct BehaviourAttributes {
852+
prelude_path: syn::Path,
853+
user_specified_out_event: Option<syn::Type>,
854+
}
855+
845856
/// Parses the `value` of a key=value pair in the `#[behaviour]` attribute into the requested type.
846-
///
847-
/// Only `String` values are supported, e.g. `#[behaviour(foo="bar")]`.
848-
fn parse_attribute_value_by_key<T>(ast: &DeriveInput, key: &str) -> Option<T>
849-
where
850-
T: Parse,
851-
{
852-
ast.attrs
857+
fn parse_attributes(ast: &DeriveInput) -> Result<BehaviourAttributes, TokenStream> {
858+
let mut attributes = BehaviourAttributes {
859+
prelude_path: syn::parse_quote! { ::libp2p::swarm::derive_prelude },
860+
user_specified_out_event: None,
861+
};
862+
863+
for attr in ast
864+
.attrs
853865
.iter()
854-
.filter_map(get_meta_items)
855-
.flatten()
856-
.filter_map(|meta_item| {
857-
if let syn::NestedMeta::Meta(syn::Meta::NameValue(ref m)) = meta_item {
858-
if m.path.is_ident(key) {
859-
if let syn::Lit::Str(ref s) = m.lit {
860-
return Some(syn::parse_str(&s.value()).unwrap());
866+
.filter(|attr| attr.path().is_ident("behaviour"))
867+
{
868+
let nested = attr
869+
.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)
870+
.expect("`parse_args_with` never fails when parsing nested meta");
871+
872+
for meta in nested {
873+
if meta.path().is_ident("prelude") {
874+
match meta {
875+
Meta::Path(_) => unimplemented!(),
876+
Meta::List(_) => unimplemented!(),
877+
Meta::NameValue(MetaNameValue {
878+
value:
879+
Expr::Lit(ExprLit {
880+
lit: Lit::Str(s), ..
881+
}),
882+
..
883+
}) => {
884+
attributes.prelude_path = syn::parse_str(&s.value()).unwrap();
885+
}
886+
Meta::NameValue(name_value) => {
887+
return Err(syn::Error::new_spanned(
888+
name_value.value,
889+
"`prelude` value must be a quoted path",
890+
)
891+
.to_compile_error()
892+
.into());
861893
}
862894
}
895+
896+
continue;
863897
}
864-
None
865-
})
866-
.next()
867-
}
868898

869-
fn get_meta_items(attr: &syn::Attribute) -> Option<Vec<syn::NestedMeta>> {
870-
if attr.path.segments.len() == 1 && attr.path.segments[0].ident == "behaviour" {
871-
match attr.parse_meta() {
872-
Ok(syn::Meta::List(ref meta)) => Some(meta.nested.iter().cloned().collect()),
873-
Ok(_) => None,
874-
Err(e) => {
875-
eprintln!("error parsing attribute metadata: {e}");
876-
None
899+
if meta.path().is_ident("out_event") {
900+
match meta {
901+
Meta::Path(_) => unimplemented!(),
902+
Meta::List(_) => unimplemented!(),
903+
904+
Meta::NameValue(MetaNameValue {
905+
value:
906+
Expr::Lit(ExprLit {
907+
lit: Lit::Str(s), ..
908+
}),
909+
..
910+
}) => {
911+
attributes.user_specified_out_event =
912+
Some(syn::parse_str(&s.value()).unwrap());
913+
}
914+
Meta::NameValue(name_value) => {
915+
return Err(syn::Error::new_spanned(
916+
name_value.value,
917+
"`out_event` value must be a quoted type",
918+
)
919+
.to_compile_error()
920+
.into());
921+
}
922+
}
923+
924+
continue;
877925
}
878926
}
879-
} else {
880-
None
881927
}
928+
929+
Ok(attributes)
882930
}

swarm/tests/swarm_derive.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,27 @@ fn generated_out_event_derive_debug() {
433433
require_debug::<Foo>();
434434
}
435435

436+
#[test]
437+
fn multiple_behaviour_attributes() {
438+
#[allow(dead_code)]
439+
#[derive(NetworkBehaviour)]
440+
#[behaviour(out_event = "FooEvent")]
441+
#[behaviour(prelude = "libp2p_swarm::derive_prelude")]
442+
struct Foo {
443+
ping: ping::Behaviour,
444+
}
445+
446+
require_net_behaviour::<Foo>();
447+
448+
struct FooEvent;
449+
450+
impl From<ping::Event> for FooEvent {
451+
fn from(_: ping::Event) -> Self {
452+
unimplemented!()
453+
}
454+
}
455+
}
456+
436457
#[test]
437458
fn custom_out_event_no_type_parameters() {
438459
use libp2p_identity::PeerId;

0 commit comments

Comments
 (0)