libp2p_swarm_derive/
lib.rs

1// Copyright 2018 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21#![recursion_limit = "256"]
22#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
23
24mod syn_ext;
25
26use crate::syn_ext::RequireStrLit;
27use heck::ToUpperCamelCase;
28use proc_macro::TokenStream;
29use quote::quote;
30use syn::punctuated::Punctuated;
31use syn::spanned::Spanned;
32use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Meta, Token};
33
34/// Generates a delegating `NetworkBehaviour` implementation for the struct this is used for. See
35/// the trait documentation for better description.
36#[proc_macro_derive(NetworkBehaviour, attributes(behaviour))]
37pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
38    let ast = parse_macro_input!(input as DeriveInput);
39    build(&ast).unwrap_or_else(|e| e.to_compile_error().into())
40}
41
42/// The actual implementation.
43fn build(ast: &DeriveInput) -> syn::Result<TokenStream> {
44    match ast.data {
45        Data::Struct(ref s) => build_struct(ast, s),
46        Data::Enum(_) => Err(syn::Error::new_spanned(
47            ast,
48            "Cannot derive `NetworkBehaviour` on enums",
49        )),
50        Data::Union(_) => Err(syn::Error::new_spanned(
51            ast,
52            "Cannot derive `NetworkBehaviour` on union",
53        )),
54    }
55}
56
57/// The version for structs
58fn build_struct(ast: &DeriveInput, data_struct: &DataStruct) -> syn::Result<TokenStream> {
59    let name = &ast.ident;
60    let (_, ty_generics, where_clause) = ast.generics.split_for_impl();
61    let BehaviourAttributes {
62        prelude_path,
63        user_specified_out_event,
64        deprecation_tokenstream,
65    } = parse_attributes(ast)?;
66
67    let multiaddr = quote! { #prelude_path::Multiaddr };
68    let trait_to_impl = quote! { #prelude_path::NetworkBehaviour };
69    let either_ident = quote! { #prelude_path::Either };
70    let network_behaviour_action = quote! { #prelude_path::ToSwarm };
71    let connection_handler = quote! { #prelude_path::ConnectionHandler };
72    let proto_select_ident = quote! { #prelude_path::ConnectionHandlerSelect };
73    let peer_id = quote! { #prelude_path::PeerId };
74    let connection_id = quote! { #prelude_path::ConnectionId };
75    let poll_parameters = quote! { #prelude_path::PollParameters };
76    let from_swarm = quote! { #prelude_path::FromSwarm };
77    let connection_established = quote! { #prelude_path::ConnectionEstablished };
78    let address_change = quote! { #prelude_path::AddressChange };
79    let connection_closed = quote! { #prelude_path::ConnectionClosed };
80    let dial_failure = quote! { #prelude_path::DialFailure };
81    let listen_failure = quote! { #prelude_path::ListenFailure };
82    let new_listener = quote! { #prelude_path::NewListener };
83    let new_listen_addr = quote! { #prelude_path::NewListenAddr };
84    let expired_listen_addr = quote! { #prelude_path::ExpiredListenAddr };
85    let new_external_addr_candidate = quote! { #prelude_path::NewExternalAddrCandidate };
86    let external_addr_expired = quote! { #prelude_path::ExternalAddrExpired };
87    let external_addr_confirmed = quote! { #prelude_path::ExternalAddrConfirmed };
88    let listener_error = quote! { #prelude_path::ListenerError };
89    let listener_closed = quote! { #prelude_path::ListenerClosed };
90    let t_handler = quote! { #prelude_path::THandler };
91    let t_handler_in_event = quote! { #prelude_path::THandlerInEvent };
92    let t_handler_out_event = quote! { #prelude_path::THandlerOutEvent };
93    let endpoint = quote! { #prelude_path::Endpoint };
94    let connection_denied = quote! { #prelude_path::ConnectionDenied };
95
96    // Build the generics.
97    let impl_generics = {
98        let tp = ast.generics.type_params();
99        let lf = ast.generics.lifetimes();
100        let cst = ast.generics.const_params();
101        quote! {<#(#lf,)* #(#tp,)* #(#cst,)*>}
102    };
103
104    let (out_event_name, out_event_definition, out_event_from_clauses) = {
105        // If we find a `#[behaviour(to_swarm = "Foo")]` attribute on the
106        // struct, we set `Foo` as the out event. If not, the `ToSwarm` is
107        // generated.
108        match user_specified_out_event {
109            // User provided `ToSwarm`.
110            Some(name) => {
111                let definition = None;
112                let from_clauses = data_struct
113                    .fields
114                    .iter()
115                    .map(|field| {
116                        let ty = &field.ty;
117                        quote! {#name: From< <#ty as #trait_to_impl>::ToSwarm >}
118                    })
119                    .collect::<Vec<_>>();
120                (name, definition, from_clauses)
121            }
122            // User did not provide `ToSwarm`. Generate it.
123            None => {
124                let enum_name_str = ast.ident.to_string() + "Event";
125                let enum_name: syn::Type =
126                    syn::parse_str(&enum_name_str).expect("ident + `Event` is a valid type");
127                let definition = {
128                    let fields = data_struct.fields.iter().map(|field| {
129                        let variant: syn::Variant = syn::parse_str(
130                            &field
131                                .ident
132                                .clone()
133                                .expect("Fields of NetworkBehaviour implementation to be named.")
134                                .to_string()
135                                .to_upper_camel_case(),
136                        )
137                        .expect("uppercased field name to be a valid enum variant");
138                        let ty = &field.ty;
139                        (variant, ty)
140                    });
141
142                    let enum_variants = fields
143                        .clone()
144                        .map(|(variant, ty)| quote! {#variant(<#ty as #trait_to_impl>::ToSwarm)});
145
146                    let visibility = &ast.vis;
147
148                    let additional = fields
149                        .clone()
150                        .map(|(_variant, tp)| quote! { #tp : #trait_to_impl })
151                        .collect::<Vec<_>>();
152
153                    let additional_debug = fields
154                        .clone()
155                        .map(|(_variant, ty)| quote! { <#ty as #trait_to_impl>::ToSwarm : ::core::fmt::Debug })
156                        .collect::<Vec<_>>();
157
158                    let where_clause = {
159                        if let Some(where_clause) = where_clause {
160                            if where_clause.predicates.trailing_punct() {
161                                Some(quote! {#where_clause #(#additional),* })
162                            } else {
163                                Some(quote! {#where_clause, #(#additional),*})
164                            }
165                        } else if additional.is_empty() {
166                            None
167                        } else {
168                            Some(quote! {where #(#additional),*})
169                        }
170                    };
171
172                    let where_clause_debug = where_clause
173                        .as_ref()
174                        .map(|where_clause| quote! {#where_clause, #(#additional_debug),*});
175
176                    let match_variants = fields.map(|(variant, _ty)| variant);
177                    let msg = format!("`NetworkBehaviour::ToSwarm` produced by {name}.");
178
179                    Some(quote! {
180                        #[doc = #msg]
181                        #visibility enum #enum_name #ty_generics
182                            #where_clause
183                        {
184                            #(#enum_variants),*
185                        }
186
187                        impl #impl_generics ::core::fmt::Debug for #enum_name #ty_generics #where_clause_debug {
188                            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
189                                match &self {
190                                    #(#enum_name::#match_variants(event) => {
191                                        write!(f, "{}: {:?}", #enum_name_str, event)
192                                    }),*
193                                }
194                            }
195                        }
196                    })
197                };
198                let from_clauses = vec![];
199                (enum_name, definition, from_clauses)
200            }
201        }
202    };
203
204    // Build the `where ...` clause of the trait implementation.
205    let where_clause = {
206        let additional = data_struct
207            .fields
208            .iter()
209            .map(|field| {
210                let ty = &field.ty;
211                quote! {#ty: #trait_to_impl}
212            })
213            .chain(out_event_from_clauses)
214            .collect::<Vec<_>>();
215
216        if let Some(where_clause) = where_clause {
217            if where_clause.predicates.trailing_punct() {
218                Some(quote! {#where_clause #(#additional),* })
219            } else {
220                Some(quote! {#where_clause, #(#additional),*})
221            }
222        } else {
223            Some(quote! {where #(#additional),*})
224        }
225    };
226
227    // Build the list of statements to put in the body of `on_swarm_event()`
228    // for the `FromSwarm::ConnectionEstablished` variant.
229    let on_connection_established_stmts = {
230        data_struct
231            .fields
232            .iter()
233            .enumerate()
234            .map(|(field_n, field)| match field.ident {
235                Some(ref i) => quote! {
236                    self.#i.on_swarm_event(#from_swarm::ConnectionEstablished(#connection_established {
237                        peer_id,
238                        connection_id,
239                        endpoint,
240                        failed_addresses,
241                        other_established,
242                    }));
243                },
244                None => quote! {
245                    self.#field_n.on_swarm_event(#from_swarm::ConnectionEstablished(#connection_established {
246                        peer_id,
247                        connection_id,
248                        endpoint,
249                        failed_addresses,
250                        other_established,
251                    }));
252                },
253            })
254    };
255
256    // Build the list of statements to put in the body of `on_swarm_event()`
257    // for the `FromSwarm::AddressChange variant`.
258    let on_address_change_stmts = {
259        data_struct
260            .fields
261            .iter()
262            .enumerate()
263            .map(|(field_n, field)| match field.ident {
264                Some(ref i) => quote! {
265                self.#i.on_swarm_event(#from_swarm::AddressChange(#address_change {
266                        peer_id,
267                        connection_id,
268                        old,
269                        new,
270                    }));
271                },
272                None => quote! {
273                self.#field_n.on_swarm_event(#from_swarm::AddressChange(#address_change {
274                        peer_id,
275                        connection_id,
276                        old,
277                        new,
278                    }));
279                },
280            })
281    };
282
283    // Build the list of statements to put in the body of `on_swarm_event()`
284    // for the `FromSwarm::ConnectionClosed` variant.
285    let on_connection_closed_stmts = {
286        data_struct
287            .fields
288            .iter()
289            .enumerate()
290            // The outmost handler belongs to the last behaviour.
291            .rev()
292            .enumerate()
293            .map(|(enum_n, (field_n, field))| {
294                let handler = if field_n == 0 {
295                    // Given that the iterator is reversed, this is the innermost handler only.
296                    quote! { let handler = handlers }
297                } else {
298                    quote! {
299                        let (handlers, handler) = handlers.into_inner()
300                    }
301                };
302                let inject = match field.ident {
303                    Some(ref i) => quote! {
304                    self.#i.on_swarm_event(#from_swarm::ConnectionClosed(#connection_closed {
305                            peer_id,
306                            connection_id,
307                            endpoint,
308                            handler,
309                            remaining_established,
310                        }));
311                    },
312                    None => quote! {
313                    self.#enum_n.on_swarm_event(#from_swarm::ConnectionClosed(#connection_closed {
314                            peer_id,
315                            connection_id,
316                            endpoint,
317                            handler,
318                            remaining_established,
319                        }));
320                    },
321                };
322
323                quote! {
324                    #handler;
325                    #inject;
326                }
327            })
328    };
329
330    // Build the list of statements to put in the body of `on_swarm_event()`
331    // for the `FromSwarm::DialFailure` variant.
332    let on_dial_failure_stmts = data_struct
333        .fields
334        .iter()
335        .enumerate()
336        .map(|(enum_n, field)| match field.ident {
337            Some(ref i) => quote! {
338                self.#i.on_swarm_event(#from_swarm::DialFailure(#dial_failure {
339                    peer_id,
340                    connection_id,
341                    error,
342                }));
343            },
344            None => quote! {
345                self.#enum_n.on_swarm_event(#from_swarm::DialFailure(#dial_failure {
346                    peer_id,
347                    connection_id,
348                    error,
349                }));
350            },
351        });
352
353    // Build the list of statements to put in the body of `on_swarm_event()`
354    // for the `FromSwarm::ListenFailure` variant.
355    let on_listen_failure_stmts = data_struct
356        .fields
357        .iter()
358        .enumerate()
359        .map(|(enum_n, field)| match field.ident {
360            Some(ref i) => quote! {
361                self.#i.on_swarm_event(#from_swarm::ListenFailure(#listen_failure {
362                    local_addr,
363                    send_back_addr,
364                    connection_id,
365                    error
366                }));
367            },
368            None => quote! {
369                self.#enum_n.on_swarm_event(#from_swarm::ListenFailure(#listen_failure {
370                    local_addr,
371                    send_back_addr,
372                    connection_id,
373                    error
374                }));
375            },
376        });
377
378    // Build the list of statements to put in the body of `on_swarm_event()`
379    // for the `FromSwarm::NewListener` variant.
380    let on_new_listener_stmts = {
381        data_struct
382            .fields
383            .iter()
384            .enumerate()
385            .map(|(field_n, field)| match field.ident {
386                Some(ref i) => quote! {
387                self.#i.on_swarm_event(#from_swarm::NewListener(#new_listener {
388                        listener_id,
389                    }));
390                },
391                None => quote! {
392                self.#field_n.on_swarm_event(#from_swarm::NewListener(#new_listener {
393                        listener_id,
394                    }));
395                },
396            })
397    };
398
399    // Build the list of statements to put in the body of `on_swarm_event()`
400    // for the `FromSwarm::NewListenAddr` variant.
401    let on_new_listen_addr_stmts = {
402        data_struct
403            .fields
404            .iter()
405            .enumerate()
406            .map(|(field_n, field)| match field.ident {
407                Some(ref i) => quote! {
408                self.#i.on_swarm_event(#from_swarm::NewListenAddr(#new_listen_addr {
409                        listener_id,
410                        addr,
411                    }));
412                },
413                None => quote! {
414                self.#field_n.on_swarm_event(#from_swarm::NewListenAddr(#new_listen_addr {
415                        listener_id,
416                        addr,
417                    }));
418                },
419            })
420    };
421
422    // Build the list of statements to put in the body of `on_swarm_event()`
423    // for the `FromSwarm::ExpiredListenAddr` variant.
424    let on_expired_listen_addr_stmts = {
425        data_struct
426            .fields
427            .iter()
428            .enumerate()
429            .map(|(field_n, field)| match field.ident {
430                Some(ref i) => quote! {
431                self.#i.on_swarm_event(#from_swarm::ExpiredListenAddr(#expired_listen_addr {
432                        listener_id,
433                        addr,
434                    }));
435                },
436                None => quote! {
437                self.#field_n.on_swarm_event(#from_swarm::ExpiredListenAddr(#expired_listen_addr {
438                        listener_id,
439                        addr,
440                    }));
441                },
442            })
443    };
444
445    // Build the list of statements to put in the body of `on_swarm_event()`
446    // for the `FromSwarm::NewExternalAddr` variant.
447    let on_new_external_addr_candidate_stmts = {
448        data_struct
449            .fields
450            .iter()
451            .enumerate()
452            .map(|(field_n, field)| match field.ident {
453                Some(ref i) => quote! {
454                self.#i.on_swarm_event(#from_swarm::NewExternalAddrCandidate(#new_external_addr_candidate {
455                        addr,
456                    }));
457                },
458                None => quote! {
459                self.#field_n.on_swarm_event(#from_swarm::NewExternalAddrCandidate(#new_external_addr_candidate {
460                        addr,
461                    }));
462                },
463            })
464    };
465
466    // Build the list of statements to put in the body of `on_swarm_event()`
467    // for the `FromSwarm::ExternalAddrExpired` variant.
468    let on_external_addr_expired_stmts = {
469        data_struct
470            .fields
471            .iter()
472            .enumerate()
473            .map(|(field_n, field)| match field.ident {
474                Some(ref i) => quote! {
475                self.#i.on_swarm_event(#from_swarm::ExternalAddrExpired(#external_addr_expired {
476                        addr,
477                    }));
478                },
479                None => quote! {
480                self.#field_n.on_swarm_event(#from_swarm::ExternalAddrExpired(#external_addr_expired {
481                        addr,
482                    }));
483                },
484            })
485    };
486
487    // Build the list of statements to put in the body of `on_swarm_event()`
488    // for the `FromSwarm::ExternalAddrConfirmed` variant.
489    let on_external_addr_confirmed_stmts = {
490        data_struct
491            .fields
492            .iter()
493            .enumerate()
494            .map(|(field_n, field)| match field.ident {
495                Some(ref i) => quote! {
496                self.#i.on_swarm_event(#from_swarm::ExternalAddrConfirmed(#external_addr_confirmed {
497                        addr,
498                    }));
499                },
500                None => quote! {
501                self.#field_n.on_swarm_event(#from_swarm::ExternalAddrConfirmed(#external_addr_confirmed {
502                        addr,
503                    }));
504                },
505            })
506    };
507
508    // Build the list of statements to put in the body of `on_swarm_event()`
509    // for the `FromSwarm::ListenerError` variant.
510    let on_listener_error_stmts = {
511        data_struct
512            .fields
513            .iter()
514            .enumerate()
515            .map(|(field_n, field)| match field.ident {
516                Some(ref i) => quote! {
517                    self.#i.on_swarm_event(#from_swarm::ListenerError(#listener_error {
518                        listener_id,
519                        err,
520                    }));
521                },
522                None => quote! {
523                    self.#field_n.on_swarm_event(#from_swarm::ListenerError(#listener_error {
524                        listener_id,
525                        err,
526                    }));
527                },
528            })
529    };
530
531    // Build the list of statements to put in the body of `on_swarm_event()`
532    // for the `FromSwarm::ListenerClosed` variant.
533    let on_listener_closed_stmts = {
534        data_struct
535            .fields
536            .iter()
537            .enumerate()
538            .map(|(field_n, field)| match field.ident {
539                Some(ref i) => quote! {
540                self.#i.on_swarm_event(#from_swarm::ListenerClosed(#listener_closed {
541                        listener_id,
542                        reason,
543                    }));
544                },
545                None => quote! {
546                self.#field_n.on_swarm_event(#from_swarm::ListenerClosed(#listener_closed {
547                        listener_id,
548                        reason,
549                    }));
550                },
551            })
552    };
553
554    // Build the list of variants to put in the body of `on_connection_handler_event()`.
555    //
556    // The event type is a construction of nested `#either_ident`s of the events of the children.
557    // We call `on_connection_handler_event` on the corresponding child.
558    let on_node_event_stmts =
559        data_struct
560            .fields
561            .iter()
562            .enumerate()
563            .enumerate()
564            .map(|(enum_n, (field_n, field))| {
565                let mut elem = if enum_n != 0 {
566                    quote! { #either_ident::Right(ev) }
567                } else {
568                    quote! { ev }
569                };
570
571                for _ in 0..data_struct.fields.len() - 1 - enum_n {
572                    elem = quote! { #either_ident::Left(#elem) };
573                }
574
575                Some(match field.ident {
576                    Some(ref i) => quote! { #elem => {
577                    #trait_to_impl::on_connection_handler_event(&mut self.#i, peer_id, connection_id, ev) }},
578                    None => quote! { #elem => {
579                    #trait_to_impl::on_connection_handler_event(&mut self.#field_n, peer_id, connection_id, ev) }},
580                })
581            });
582
583    // The [`ConnectionHandler`] associated type.
584    let connection_handler_ty = {
585        let mut ph_ty = None;
586        for field in data_struct.fields.iter() {
587            let ty = &field.ty;
588            let field_info = quote! { #t_handler<#ty> };
589            match ph_ty {
590                Some(ev) => ph_ty = Some(quote! { #proto_select_ident<#ev, #field_info> }),
591                ref mut ev @ None => *ev = Some(field_info),
592            }
593        }
594        // ph_ty = Some(quote! )
595        ph_ty.unwrap_or(quote! {()}) // TODO: `!` instead
596    };
597
598    // The content of `handle_pending_inbound_connection`.
599    let handle_pending_inbound_connection_stmts =
600        data_struct
601            .fields
602            .iter()
603            .enumerate()
604            .map(|(field_n, field)| {
605                match field.ident {
606                    Some(ref i) => quote! {
607                        #trait_to_impl::handle_pending_inbound_connection(&mut self.#i, connection_id, local_addr, remote_addr)?;
608                    },
609                    None => quote! {
610                        #trait_to_impl::handle_pending_inbound_connection(&mut self.#field_n, connection_id, local_addr, remote_addr)?;
611                    }
612                }
613            });
614
615    // The content of `handle_established_inbound_connection`.
616    let handle_established_inbound_connection = {
617        let mut out_handler = None;
618
619        for (field_n, field) in data_struct.fields.iter().enumerate() {
620            let field_name = match field.ident {
621                Some(ref i) => quote! { self.#i },
622                None => quote! { self.#field_n },
623            };
624
625            let builder = quote! {
626                #field_name.handle_established_inbound_connection(connection_id, peer, local_addr, remote_addr)?
627            };
628
629            match out_handler {
630                Some(h) => out_handler = Some(quote! { #connection_handler::select(#h, #builder) }),
631                ref mut h @ None => *h = Some(builder),
632            }
633        }
634
635        out_handler.unwrap_or(quote! {()}) // TODO: See test `empty`.
636    };
637
638    // The content of `handle_pending_outbound_connection`.
639    let handle_pending_outbound_connection = {
640        let extend_stmts =
641            data_struct
642                .fields
643                .iter()
644                .enumerate()
645                .map(|(field_n, field)| {
646                    match field.ident {
647                        Some(ref i) => quote! {
648                            combined_addresses.extend(#trait_to_impl::handle_pending_outbound_connection(&mut self.#i, connection_id, maybe_peer, addresses, effective_role)?);
649                        },
650                        None => quote! {
651                            combined_addresses.extend(#trait_to_impl::handle_pending_outbound_connection(&mut self.#field_n, connection_id, maybe_peer, addresses, effective_role)?);
652                        }
653                    }
654                });
655
656        quote! {
657            let mut combined_addresses = vec![];
658
659            #(#extend_stmts)*
660
661            Ok(combined_addresses)
662        }
663    };
664
665    // The content of `handle_established_outbound_connection`.
666    let handle_established_outbound_connection = {
667        let mut out_handler = None;
668
669        for (field_n, field) in data_struct.fields.iter().enumerate() {
670            let field_name = match field.ident {
671                Some(ref i) => quote! { self.#i },
672                None => quote! { self.#field_n },
673            };
674
675            let builder = quote! {
676                #field_name.handle_established_outbound_connection(connection_id, peer, addr, role_override)?
677            };
678
679            match out_handler {
680                Some(h) => out_handler = Some(quote! { #connection_handler::select(#h, #builder) }),
681                ref mut h @ None => *h = Some(builder),
682            }
683        }
684
685        out_handler.unwrap_or(quote! {()}) // TODO: See test `empty`.
686    };
687
688    // List of statements to put in `poll()`.
689    //
690    // We poll each child one by one and wrap around the output.
691    let poll_stmts = data_struct.fields.iter().enumerate().map(|(field_n, field)| {
692        let field = field
693            .ident
694            .clone()
695            .expect("Fields of NetworkBehaviour implementation to be named.");
696
697        let mut wrapped_event = if field_n != 0 {
698            quote!{ #either_ident::Right(event) }
699        } else {
700            quote!{ event }
701        };
702        for _ in 0 .. data_struct.fields.len() - 1 - field_n {
703            wrapped_event = quote!{ #either_ident::Left(#wrapped_event) };
704        }
705
706        let generate_event_match_arm =  {
707            // If the `NetworkBehaviour`'s `ToSwarm` is generated by the derive macro, wrap the sub
708            // `NetworkBehaviour` `ToSwarm` in the variant of the generated `ToSwarm`. If the
709            // `NetworkBehaviour`'s `ToSwarm` is provided by the user, use the corresponding `From`
710            // implementation.
711            let into_out_event = if out_event_definition.is_some() {
712                let event_variant: syn::Variant = syn::parse_str(
713                    &field
714                        .to_string()
715                        .to_upper_camel_case()
716                ).expect("uppercased field name to be a valid enum variant name");
717                quote! { #out_event_name::#event_variant(event) }
718            } else {
719                quote! { event.into() }
720            };
721
722            quote! {
723                std::task::Poll::Ready(#network_behaviour_action::GenerateEvent(event)) => {
724                    return std::task::Poll::Ready(#network_behaviour_action::GenerateEvent(#into_out_event))
725                }
726            }
727        };
728
729        quote!{
730            match #trait_to_impl::poll(&mut self.#field, cx, poll_params) {
731                #generate_event_match_arm
732                std::task::Poll::Ready(#network_behaviour_action::Dial { opts }) => {
733                    return std::task::Poll::Ready(#network_behaviour_action::Dial { opts });
734                }
735                std::task::Poll::Ready(#network_behaviour_action::ListenOn { opts }) => {
736                    return std::task::Poll::Ready(#network_behaviour_action::ListenOn { opts });
737                }
738                std::task::Poll::Ready(#network_behaviour_action::RemoveListener { id }) => {
739                    return std::task::Poll::Ready(#network_behaviour_action::RemoveListener { id });
740                }
741                std::task::Poll::Ready(#network_behaviour_action::NotifyHandler { peer_id, handler, event }) => {
742                    return std::task::Poll::Ready(#network_behaviour_action::NotifyHandler {
743                        peer_id,
744                        handler,
745                        event: #wrapped_event,
746                    });
747                }
748                std::task::Poll::Ready(#network_behaviour_action::NewExternalAddrCandidate(addr)) => {
749                    return std::task::Poll::Ready(#network_behaviour_action::NewExternalAddrCandidate(addr));
750                }
751                std::task::Poll::Ready(#network_behaviour_action::ExternalAddrConfirmed(addr)) => {
752                    return std::task::Poll::Ready(#network_behaviour_action::ExternalAddrConfirmed(addr));
753                }
754                std::task::Poll::Ready(#network_behaviour_action::ExternalAddrExpired(addr)) => {
755                    return std::task::Poll::Ready(#network_behaviour_action::ExternalAddrExpired(addr));
756                }
757                std::task::Poll::Ready(#network_behaviour_action::CloseConnection { peer_id, connection }) => {
758                    return std::task::Poll::Ready(#network_behaviour_action::CloseConnection { peer_id, connection });
759                }
760                std::task::Poll::Pending => {},
761            }
762        }
763    });
764
765    let out_event_reference = if out_event_definition.is_some() {
766        quote! { #out_event_name #ty_generics }
767    } else {
768        quote! { #out_event_name }
769    };
770
771    // Now the magic happens.
772    let final_quote = quote! {
773        #deprecation_tokenstream
774
775        #out_event_definition
776
777        impl #impl_generics #trait_to_impl for #name #ty_generics
778        #where_clause
779        {
780            type ConnectionHandler = #connection_handler_ty;
781            type ToSwarm = #out_event_reference;
782
783            #[allow(clippy::needless_question_mark)]
784            fn handle_pending_inbound_connection(
785                &mut self,
786                connection_id: #connection_id,
787                local_addr: &#multiaddr,
788                remote_addr: &#multiaddr,
789            ) -> Result<(), #connection_denied> {
790                #(#handle_pending_inbound_connection_stmts)*
791
792                Ok(())
793            }
794
795            #[allow(clippy::needless_question_mark)]
796            fn handle_established_inbound_connection(
797                &mut self,
798                connection_id: #connection_id,
799                peer: #peer_id,
800                local_addr: &#multiaddr,
801                remote_addr: &#multiaddr,
802            ) -> Result<#t_handler<Self>, #connection_denied> {
803                Ok(#handle_established_inbound_connection)
804            }
805
806            #[allow(clippy::needless_question_mark)]
807            fn handle_pending_outbound_connection(
808                &mut self,
809                connection_id: #connection_id,
810                maybe_peer: Option<#peer_id>,
811                addresses: &[#multiaddr],
812                effective_role: #endpoint,
813            ) -> Result<::std::vec::Vec<#multiaddr>, #connection_denied> {
814                #handle_pending_outbound_connection
815            }
816
817            #[allow(clippy::needless_question_mark)]
818            fn handle_established_outbound_connection(
819                &mut self,
820                connection_id: #connection_id,
821                peer: #peer_id,
822                addr: &#multiaddr,
823                role_override: #endpoint,
824            ) -> Result<#t_handler<Self>, #connection_denied> {
825                Ok(#handle_established_outbound_connection)
826            }
827
828            fn on_connection_handler_event(
829                &mut self,
830                peer_id: #peer_id,
831                connection_id: #connection_id,
832                event: #t_handler_out_event<Self>
833            ) {
834                match event {
835                    #(#on_node_event_stmts),*
836                }
837            }
838
839            fn poll(&mut self, cx: &mut std::task::Context, poll_params: &mut impl #poll_parameters) -> std::task::Poll<#network_behaviour_action<Self::ToSwarm, #t_handler_in_event<Self>>> {
840                use #prelude_path::futures::*;
841                #(#poll_stmts)*
842                std::task::Poll::Pending
843            }
844
845            fn on_swarm_event(&mut self, event: #from_swarm<Self::ConnectionHandler>) {
846                match event {
847                    #from_swarm::ConnectionEstablished(
848                        #connection_established { peer_id, connection_id, endpoint, failed_addresses, other_established })
849                    => { #(#on_connection_established_stmts)* }
850                    #from_swarm::AddressChange(
851                        #address_change { peer_id, connection_id, old, new })
852                    => { #(#on_address_change_stmts)* }
853                    #from_swarm::ConnectionClosed(
854                        #connection_closed { peer_id, connection_id, endpoint, handler: handlers, remaining_established })
855                    => { #(#on_connection_closed_stmts)* }
856                    #from_swarm::DialFailure(
857                        #dial_failure { peer_id, connection_id, error })
858                    => { #(#on_dial_failure_stmts)* }
859                    #from_swarm::ListenFailure(
860                        #listen_failure { local_addr, send_back_addr, connection_id, error })
861                    => { #(#on_listen_failure_stmts)* }
862                    #from_swarm::NewListener(
863                        #new_listener { listener_id })
864                    => { #(#on_new_listener_stmts)* }
865                    #from_swarm::NewListenAddr(
866                        #new_listen_addr { listener_id, addr })
867                    => { #(#on_new_listen_addr_stmts)* }
868                    #from_swarm::ExpiredListenAddr(
869                        #expired_listen_addr { listener_id, addr })
870                    => { #(#on_expired_listen_addr_stmts)* }
871                    #from_swarm::NewExternalAddrCandidate(
872                        #new_external_addr_candidate { addr })
873                    => { #(#on_new_external_addr_candidate_stmts)* }
874                    #from_swarm::ExternalAddrExpired(
875                        #external_addr_expired { addr })
876                    => { #(#on_external_addr_expired_stmts)* }
877                    #from_swarm::ExternalAddrConfirmed(
878                        #external_addr_confirmed { addr })
879                    => { #(#on_external_addr_confirmed_stmts)* }
880                    #from_swarm::ListenerError(
881                        #listener_error { listener_id, err })
882                    => { #(#on_listener_error_stmts)* }
883                    #from_swarm::ListenerClosed(
884                        #listener_closed { listener_id, reason })
885                    => { #(#on_listener_closed_stmts)* }
886                    _ => {}
887                }
888            }
889        }
890    };
891
892    Ok(final_quote.into())
893}
894
895struct BehaviourAttributes {
896    prelude_path: syn::Path,
897    user_specified_out_event: Option<syn::Type>,
898    deprecation_tokenstream: proc_macro2::TokenStream,
899}
900
901/// Parses the `value` of a key=value pair in the `#[behaviour]` attribute into the requested type.
902fn parse_attributes(ast: &DeriveInput) -> syn::Result<BehaviourAttributes> {
903    let mut attributes = BehaviourAttributes {
904        prelude_path: syn::parse_quote! { ::libp2p::swarm::derive_prelude },
905        user_specified_out_event: None,
906        deprecation_tokenstream: proc_macro2::TokenStream::new(),
907    };
908
909    for attr in ast
910        .attrs
911        .iter()
912        .filter(|attr| attr.path().is_ident("behaviour"))
913    {
914        let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
915
916        for meta in nested {
917            if meta.path().is_ident("prelude") {
918                let value = meta.require_name_value()?.value.require_str_lit()?;
919
920                attributes.prelude_path = syn::parse_str(&value)?;
921
922                continue;
923            }
924
925            if meta.path().is_ident("to_swarm") || meta.path().is_ident("out_event") {
926                if meta.path().is_ident("out_event") {
927                    let warning = proc_macro_warning::FormattedWarning::new_deprecated(
928                        "out_event_renamed_to_to_swarm",
929                        "The `out_event` attribute has been renamed to `to_swarm`.",
930                        meta.span(),
931                    );
932
933                    attributes.deprecation_tokenstream = quote::quote! { #warning };
934                }
935
936                let value = meta.require_name_value()?.value.require_str_lit()?;
937
938                attributes.user_specified_out_event = Some(syn::parse_str(&value)?);
939
940                continue;
941            }
942        }
943    }
944
945    Ok(attributes)
946}