diff --git a/swarm/Cargo.toml b/swarm/Cargo.toml index dfb91614..e167c53d 100644 --- a/swarm/Cargo.toml +++ b/swarm/Cargo.toml @@ -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" diff --git a/swarm/src/behaviour.rs b/swarm/src/behaviour.rs index f50b0250..b3f5b1bc 100644 --- a/swarm/src/behaviour.rs +++ b/swarm/src/behaviour.rs @@ -31,18 +31,48 @@ use std::{task::Context, task::Poll}; type THandlerInEvent = <::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)]` +/// # 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`]. +/// +/// ``` 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 `struct`, which delegates method calls to all struct members. -/// -/// Struct members that don't implement [`NetworkBehaviour`] must be annotated with `#[behaviour(ignore)]`. +/// 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")]`. @@ -50,7 +80,72 @@ type THandlerInEvent = /// 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 for Event { +/// fn from(event: IdentifyEvent) -> Self { +/// Self::Identify(event) +/// } +/// } +/// +/// impl From 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 for Event { +/// # fn from(event: IdentifyEvent) -> Self { +/// # Self::Identify(event) +/// # } +/// # } +/// # +/// # impl From 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. ///