Skip to content

Commit

Permalink
swarm/: Improve NetworkBehaviour documentation (#2361)
Browse files Browse the repository at this point in the history
- Contrast `NetworkBehaviour` and `Transport`.
- Describe hierarchy of `NetworkBehaviour` implementations.
- Describe `NetworkBehaviour` combinators.
- Describe `NetworkBehaviour` derive macro.
  - Document `out_event` mechanism`.
  - Document `ignore` mechanism.
  • Loading branch information
mxinden authored Dec 8, 2021
1 parent 2c75fbe commit b316c6d
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 10 deletions.
2 changes: 1 addition & 1 deletion swarm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ futures-timer = "3.0.2"
instant = "0.1.11"

[dev-dependencies]
libp2p = { path = "../", default-features = false, features = ["yamux", "plaintext"] }
libp2p = { path = "../", default-features = false, features = ["identify", "ping", "plaintext", "yamux"] }
quickcheck = "0.9.0"
rand = "0.7.2"
113 changes: 104 additions & 9 deletions swarm/src/behaviour.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,121 @@ use std::{task::Context, task::Poll};
type THandlerInEvent<THandler> =
<<THandler as IntoProtocolsHandler>::Handler as ProtocolsHandler>::InEvent;

/// A behaviour for the network. Allows customizing the swarm.
/// A [`NetworkBehaviour`] defines the behaviour of the local node on the network.
///
/// This trait has been designed to be composable. Multiple implementations can be combined into
/// one that handles all the behaviours at once.
/// In contrast to [`Transport`](libp2p_core::Transport) which defines **how** to send bytes on the
/// network, [`NetworkBehaviour`] defines **what** bytes to send and **to whom**.
///
/// # Deriving `NetworkBehaviour`
/// Each protocol (e.g. `libp2p-ping`, `libp2p-identify` or `libp2p-kad`) implements
/// [`NetworkBehaviour`]. Multiple implementations of [`NetworkBehaviour`] can be composed into a
/// hierarchy of [`NetworkBehaviour`]s where parent implementations delegate to child
/// implementations. Finally the root of the [`NetworkBehaviour`] hierarchy is passed to
/// [`Swarm`](crate::Swarm) where it can then control the behaviour of the local node on a libp2p
/// network.
///
/// Crate users can implement this trait by using the the `#[derive(NetworkBehaviour)]`
/// proc macro re-exported by the `libp2p` crate. The macro generates a delegating `trait`
/// implementation for the `struct`, which delegates method calls to all struct members.
/// # Hierarchy of [`NetworkBehaviour`]
///
/// To compose multiple [`NetworkBehaviour`] implementations into a single [`NetworkBehaviour`]
/// implementation, potentially building a multi-level hierarchy of [`NetworkBehaviour`]s, one can
/// use one of the [`NetworkBehaviour`] combinators, and/or use the [`NetworkBehaviour`] derive
/// macro.
///
/// ## Combinators
///
/// [`NetworkBehaviour`] combinators wrap one or more [`NetworkBehaviour`] implementations and
/// implement [`NetworkBehaviour`] themselves. Example is the [`Toggle`](crate::toggle::Toggle)
/// [`NetworkBehaviour`].
///
/// Struct members that don't implement [`NetworkBehaviour`] must be annotated with `#[behaviour(ignore)]`.
/// ``` rust
/// # use libp2p_swarm::DummyBehaviour;
/// # use libp2p_swarm::toggle::Toggle;
/// let my_behaviour = DummyBehaviour::default();
/// let my_toggled_behaviour = Toggle::from(Some(my_behaviour));
/// ```
///
/// ## Derive Macro
///
/// One can derive [`NetworkBehaviour`] for a custom `struct` via the `#[derive(NetworkBehaviour)]`
/// proc macro re-exported by the `libp2p` crate. The macro generates a delegating `trait`
/// implementation for the custom `struct`. Each [`NetworkBehaviour`] trait method is simply
/// delegated to each `struct` member in the order the `struct` is defined. For example for
/// [`NetworkBehaviour::poll`] it will first poll the first `struct` member until it returns
/// [`Poll::Pending`] before moving on to later members. For [`NetworkBehaviour::addresses_of_peer`]
/// it will delegate to each `struct` member and return a concatenated array of all addresses
/// returned by the struct members.
///
/// By default the derive sets the [`NetworkBehaviour::OutEvent`] as `()` but this can be overridden
/// with `#[behaviour(out_event = "AnotherType")]`.
///
/// When setting a custom `out_event` users have to implement [`From`] converting from each of the
/// event types generated by the struct members to the custom `out_event`.
///
/// Alternatively, users can specify `#[behaviour(event_process = true)]`. Events generated by the
/// ``` rust
/// # use libp2p::identify::{Identify, IdentifyEvent};
/// # use libp2p::ping::{Ping, PingEvent};
/// # use libp2p::NetworkBehaviour;
/// #[derive(NetworkBehaviour)]
/// #[behaviour(out_event = "Event")]
/// struct MyBehaviour {
/// identify: Identify,
/// ping: Ping,
/// }
///
/// enum Event {
/// Identify(IdentifyEvent),
/// Ping(PingEvent),
/// }
///
/// impl From<IdentifyEvent> for Event {
/// fn from(event: IdentifyEvent) -> Self {
/// Self::Identify(event)
/// }
/// }
///
/// impl From<PingEvent> for Event {
/// fn from(event: PingEvent) -> Self {
/// Self::Ping(event)
/// }
/// }
/// ```
///
/// Struct members that don't implement [`NetworkBehaviour`] must be annotated with
/// `#[behaviour(ignore)]`.
///
/// ``` rust
/// # use libp2p::identify::{Identify, IdentifyEvent};
/// # use libp2p::ping::{Ping, PingEvent};
/// # use libp2p::NetworkBehaviour;
/// #[derive(NetworkBehaviour)]
/// #[behaviour(out_event = "Event")]
/// struct MyBehaviour {
/// identify: Identify,
/// ping: Ping,
///
/// #[behaviour(ignore)]
/// some_string: String,
/// }
/// #
/// # enum Event {
/// # Identify(IdentifyEvent),
/// # Ping(PingEvent),
/// # }
/// #
/// # impl From<IdentifyEvent> for Event {
/// # fn from(event: IdentifyEvent) -> Self {
/// # Self::Identify(event)
/// # }
/// # }
/// #
/// # impl From<PingEvent> for Event {
/// # fn from(event: PingEvent) -> Self {
/// # Self::Ping(event)
/// # }
/// # }
/// ```
///
/// For users that need access to the root [`NetworkBehaviour`] implementation while processing
/// emitted events, one can specify `#[behaviour(event_process = true)]`. Events generated by the
/// struct members are delegated to [`NetworkBehaviourEventProcess`] implementations. Those must be
/// provided by the user on the type that [`NetworkBehaviour`] is derived on.
///
Expand Down

0 comments on commit b316c6d

Please sign in to comment.