<h1> Coding Guides </h1>

<h2> Table of Contents </h2>

- [Introduction](#introduction)
- [Module Structure](#module-structure)
  - [Example](#example)
- [Naming Conventions](#naming-conventions)
- [`error` Handling](#error-handling)
- [`logs`](#logs)
- [Function Signatures](#function-signatures)
  - [Examples](#examples)

---

## Introduction

We present coding guides for the reliable message bus (RMB).

> This document will always be `work in progress`. [Read the official docs for updates](https://github.com/threefoldtech/rmb-rs/blob/main/docs/code-guide.md).
## Module Structure

In Rust there are multiple ways to create a (sub)module in your crate

- `<module>.rs`  A single file module. can be imported in `main.rs` or `lib.rs` with the keyword `mod`
- `<module>/mod.rs` A directory module. Uses mod.rs as the module `entrypoint` always. Other sub-modules can be created next to mod.rs and can be made available by using the `mod` keyword again in the `mod.rs` file.

We will agree to use the 2nd way (directory) but with the following restrictions:

- `mod.rs` will have all `traits` and `concrete types` used by the traits.
- `<implementation>.rs` file next to `mod.rs` that can include implementation for the module trait.
z

### Example

Following is an example of `animal` module.

```
animal/
   mod.rs
   dog.rs
   cat.rs
```

> File names are always in `snake_case` but avoid the `_` as much as possible because they basically look ugly in file tree. For example we prefer the name `dog.rs` over `dog_animal.rs` because we already can tell from the module name that it's a `dog` __animal__. Hence in the identity module for example the name `ed25519.rs` is preferred over `ed25519_identity.rs` because that's already inferred from the module name.
The `mod.rs` file then can contain

```rust
pub mod dog;
pub mod cat;
pub use dog::Dog;

pub trait Food {
    fn calories(&self) -> u32;
}

pub trait Animal<F>
where
    F: Food,
{
    fn feed(&mut self, food: F);
}

```

The `dog.rs` file then can contain

```rust
use super::{Animal, Food};

pub struct DogFood {}
impl Food for DogFood {
    fn calories(&self) -> u32 {
        1000
    }
}
pub struct Dog {}

impl Animal<DogFood> for Dog {
    fn feed(&mut self, food: DogFood) {
        println!("yum yum yum {} calories", food.calories());
    }
}

```

A user of the module now can do

```
use animal::dog::{Dog, DogFood};
```

For common implementation that are usually used in your modules, a `pub use` can be added in `mod.rs` to make it easier to import your type. For example

```rust
// dog is brought directly from animal crate
use animal::Dog;
// cat i need to get from the sub-module
use animal::cat::Cat;
```

## Naming Conventions

Following the rust guide lines for name

- `file names` are short snake case. avoid `_` if otherwise name will not be descriptive. Check note about file names above.
- `trait`, `struct`, `enum` names are all `CamelCase`
- `fn`, `variables` names are snake case

Note, names of functions and variables need to be `descriptive` but __short__ at the same time. Also avoid the `_` until absolutely necessary. A variable with a single `word` name is better if it doesn't cause confusion with other variables in the same context.

The name of the variable should never include the `type`.

## `error` Handling

We agreed to use `anyhow` crate in this project. Please read the docs for [`anyhow`](https://docs.rs/anyhow/1.0.57/anyhow/)

To unify the practice by default we import both `Result` and `Context` from `anyhow`
> Others can be imported as well if needed.
```rust
use anyhow::{Result, Context};

fn might_fail() -> Result<()> {
    // context adds a `context` to the error. so if another_call fails. I can tell exactly failed when i was doing what
    another_call().context("failed to do something")?; // <- we use ? to propagate the error unless you need to handle the error differently

    Ok(()) // we use Ok from std no need to import anyhow::Ok although it's probably the same.
}

fn might_fail2() -> Result<()> {
    if fail {
        // use the bail macro fom anyhow to exit with an error.
        bail!("failed because fail with set to true");
    }
}

> NOTE: all error messages starts with lowercase. for example it's `failed to ...` not `Failed to ...`
```

## `logs`

logging is important to trace the errors that cannot be propagated and also for debug messages that can help spotting a problem. We always gonna use `log` crate. as

```rust
log::debug!(); // for debug messages
log::info!(); // info messages
```

Note only `errors` that can __NOT__ be propagated are logged.

> NOTE: All log messages start with lowercase.
## Function Signatures

For function inputs (arguments) `generic` types are preferred if available over concrete types. This most obvious with `string` types. depending on the function behavior

### Examples

This is bad:

```rust
fn call1(key: String);
fn call2(key: &str);
```

It is preferred to use:

```rust
// in case function will need to take ownership of the string.
fn call1<k: Into<String>>(k: K);
// inc ase function will just need to use a reference to the string.
fn call2<K: AsRef<str>>(k: K);

// this will allow both functions to be callable with `&str`, `String`.
```