# Coding Guidelines
**Table of Contents**
- [Coding Guidelines](#coding-guidelines)
- [Hierarchical State Machines](#hierarchical-state-machines)
- [Conventions for `poll` implementations](#conventions-for-poll-implementations)
- [Prioritize local work over new work from a remote](#prioritize-local-work-over-new-work-from-a-remote)
- [Bound everything](#bound-everything)
- [Channels](#channels)
- [Local queues](#local-queues)
- [Tasks](#tasks)
- [Further reading](#further-reading)
- [No premature optimizations](#no-premature-optimizations)
- [Keep things sequential unless proven to be slow](#keep-things-sequential-unless-proven-to-be-slow)
- [Use `async/await` for sequential execution only](#use-asyncawait-for-sequential-execution-only)
- [Don't communicate by sharing memory; share memory by communicating.](#dont-communicate-by-sharing-memory-share-memory-by-communicating)
- [Further Reading](#further-reading)
- [Use iteration not recursion](#use-iteration-not-recursion)
- [Further Reading](#further-reading-1)
- [Allow Correlating Asynchronous Responses to Their Requests](#allow-correlating-asynchronous-responses-to-their-requests)
Below is a set of coding guidelines followed across the rust-libp2p code base.
## Hierarchical State Machines
If you sqint, rust-libp2p is just a big hierarchy of [state
machines](https://en.wikipedia.org/wiki/Finite-state_machine) where parents pass
events down to their children and children pass events up to their parents.

Reproduce diagram
```
@startuml
Swarm <|-- RootBehaviour
Swarm <|-- ConnectionPool
Swarm <|-- Transport
RootBehaviour <|-- PingBehaviour
RootBehaviour <|-- IdentifyBehaviour
RootBehaviour <|-- KademliaBehaviour
Swarm : poll()
RootBehaviour : poll()
ConnectionPool : poll()
Transport : poll()
PingBehaviour : poll()
IdentifyBehaviour : poll()
KademliaBehaviour : poll()
@enduml
```
Using hierarchical state machines is a deliberate choice throughout the
rust-libp2p code base. It makes reasoning about control and data flow simple. It
works well with Rust's `Future` model. It allows fine-grain control e.g. on the
order child state machines are polled.
The above comes with downsides. It feels more verbose. The mix of control flow (`loop`, `return`,
`break`, `continue`) in `poll` functions together with the asynchronous and thus decoupled
communication via events can be very hard to understand. Both are a form of complexity that we are
trading for correctness and performance which aligns with Rust's and rust-libp2p's goals.
The architecture pattern of hierarchical state machines should be used wherever possible.
### Conventions for `poll` implementations
The `poll` method of a single state machine can be complex especially when that
state machine itself `poll`s many child state machines. The patterns shown below
have proven useful and should be followed across the code base.
``` rust
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll{
loop {
match self.child_1.poll(cx) {
// The child made progress.
Poll::Ready(_) => {
// Either return an event to the parent:
return Poll::Ready(todo!());
// or `continue`, thus polling `child_1` again. `child_1` can potentially make more progress. Try to exhaust
// it before moving on to the next child.
continue
// but NEVER move to the next child if the current child made progress. Given
// that the current child might be able to make more progress, it did not yet
// register the waker in order for the root task to be woken up later on. Moving
// on to the next child might result in the larger `Future` task to stall as it
// assumes that there is no more progress to be made.
}
// The child did not make progress. It has registered the waker for a
// later wake up. Proceed with the other children.
Poll::Pending(_) => {}
}
match self.child_2.poll(cx) {
Poll::Ready(child_2_event) => {
// Events can be dispatched from one child to the other.
self.child_1.handle_event(child_2_event);
// Either `continue` thus polling `child_1` again, or `return Poll::Ready` with a result to the parent.
todo!()
}
Poll::Pending(_) => {}
}
match self.child_3.poll(cx) {
Poll::Ready(__) => {
// Either `continue` thus polling `child_1` again, or `return Poll::Ready` with a result to the parent.
todo!()
}
Poll::Pending(_) => {}
}
// None of the child state machines can make any more progress. Each registered
// the waker in order for the root `Future` task to be woken up again.
return Poll::Pending
}
}
```
### Prioritize local work over new work from a remote
When handling multiple work streams, prioritize local work items over
accepting new work items from a remote. Take the following state machine as an
example, reading and writing from a socket, returning result to its parent:
``` rust
struct SomeStateMachine {
socket: Socket,
events_to_return_to_parent: VecDeque,
messages_to_send_on_socket: VecDeque,
}
impl Stream for SomeStateMachine {
type Item = Event;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll