Skip to content

Commit

Permalink
Merge pull request #538 from threefoldtech/development_rmb
Browse files Browse the repository at this point in the history
updated rmb section
  • Loading branch information
khaledyoussef24 committed May 30, 2024
2 parents a7111a5 + a664433 commit 5ffe23e
Show file tree
Hide file tree
Showing 8 changed files with 442 additions and 73 deletions.
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
- [Internals](documentation/developers/internals/internals.md)
- [Reliable Message Bus (RMB)](documentation/developers/internals/rmb/rmb_toc.md)
- [Introduction to RMB](documentation/developers/internals/rmb/rmb_intro.md)
- [Coding Guides](documentation/developers/internals/rmb/rmb_coding_guides.md)
- [RMB Specs](documentation/developers/internals/rmb/rmb_specs.md)
- [RMB Peer](documentation/developers/internals/rmb/uml/peer.md)
- [RMB Relay](documentation/developers/internals/rmb/uml/relay.md)
Expand Down
1 change: 1 addition & 0 deletions src/documentation/developers/internals/internals.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ We present in this section of the developers book a partial list of system compo

- [Reliable Message Bus (RMB)](rmb/rmb_toc.md)
- [Introduction to RMB](rmb/rmb_intro.md)
- [Coding Guides](rmb/rmb_coding_guides.md)
- [RMB Specs](rmb/rmb_specs.md)
- [RMB Peer](rmb/uml/peer.md)
- [RMB Relay](rmb/uml/relay.md)
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
178 changes: 178 additions & 0 deletions src/documentation/developers/internals/rmb/rmb_coding_guides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<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`.
```
Loading

0 comments on commit 5ffe23e

Please sign in to comment.