# Thanix Code Style Guide
## General Guide
In regards to formatting, we follow the current Rust code style set by the Cargo
formatter (`cargo fmt`).
The easiest way to enforce this, is using `pre-commit` to automatically format
and check any code before it is committed.
```admonish info
This style is enforced by our CI as well. PRs will not be accepted unless the formatting issues are fixed.
```
## Focus on Readability
When writing code, we value readability above complexity.
Rust offers a lot of possibilities when it comes to reducing code down into a
one-line statement. And that's nice, and sometimes even necessary.
However, we want to take a **readability first** approach with our codebase.
Both to aid maintainability and increase accessibility for newcomers.
Of course, sometimes using Rust's more "advanced" features will drastically
improve performance. So a balance has to be struck between readability and
performance. It is very hard to define a solid policy for this, so this is a
decision every developer and contributor has to do for themselves and - when
necessary - engage in discussion with maintainers, devs and other contributors
about their approach and possible alternatives.
## Documenting Code
For a similar reason, we encourage devs to properly document their
contributions. This includes but is not limited to:
- Using inline comments to explain possibly hard to understand syntax
- Using Rust's powerful docstring feature to properly document functions,
structs and modules
- Adding to this documentation when applicable
- Filling out Issue and PR templates appropriately to aid maintainers review
their changes
The following examples will show you an ideal docstring style.
````admonish example title="Example: Documenting Functions" collapsible=true
**Documenting Functions:**
```rust
/// This function does X.
///
/// This function does X by doing Y using Z. (Detailed explanation optional)
///
/// # Parameters
/// * `arg: str` - A string argument to process
///
/// # Returns
/// * `Ok(str)` - Returns A, if ...
/// * `Err` - Returns an `ErrType`
pub fn foo(arg: str) -> Result<str, Err> {
// ...
}
```
While not universally used by all projects, we use `# Parameters` and `# Returns`
sections, especially for larger functions.
If a function does not take arguments, the `# Parameters` section can be omitted.
However, if the function does not return (`!` type) - or returns `()`, this has to be indicated
in the `# Returns` section.
Other sections we use are:
* `# Aborts` - If the function aborts the program. (E.g When input parameters are missing)
* `# Panics` - If the function can cause a `panic!()`.
For both of these sections, list all - or at least the most common - reasons this behaviour can
occur. This can help debugging immensely.
```rust
/// This function does X.
///
/// # Parameters
/// - `path: &str` - The path to a file
///
/// # Returns
/// - `String` - The contents of the file.
///
/// # Aborts
/// This function will exit the process if the file cannot be found.
pub fn read_file(path: &str) -> String {
match fs::read_to_string(path) {
Ok(contents) => contents,
Err(err) => {
eprintln!("[Error] File '{}' does not exist: {}", path, err);
process::exit(1);
}
}
}
```
````
````admonish example title="Example: Documenting Structs" collapsible=true
**Documenting Structs:**
```rust
/// Information about a Person.
pub struct Person {
/// The name of the Person.
pub name: String,
/// The age of the Person.
pub age: i64,
}
```
It is encouraged to briefly document every field of your struct, whether they are `pub`
or not does not matter.
````
````admonish example title="Example: Documenting Modules" collapsible=true
**Documenting Modules:**
```rust
//! This module handles X.
```
You can go into depth here about what a module does. This is encouraged for larger modules.
````
```admonish hint
Please be aware, that a one-liner docstring above a function **will not suffice**.
Maintainers may ask you to stick to the given format for your contribution.
```
We are aware that to some of you, this feels like cluttering the code files.
However, we believe that properly documenting our code is the key to providing a
more inclusive and more maintainable development experience for all.
## Terminal Output/User Interface
When it is necessary to inform the user about a process, we want to make it
short, but as expressive as possible. For this, the following styles apply:
- `Process X has been started...` - Basic white text indicates the current
process.
- `\x1b[32m[success]\x1b[0m Something has succeeded` - Green colored `[success]`
prefix before the message.
- `\x1b[31m[error]\x1b[0m Something has failed!` - Red colored `[error]` prefix
before error message. _This should automatically be added by our custom error
types when they are given a error message._
- `\x1b[36m[info]\x1b[0m Information level message.` - Light blue colored
`[info]` prefix.
- `\x1b[33m[warning]\x1b[0m Something went wrong, but we can continue...` -
Yellow colored `[warning]` prefix.
````admonish example title="Example: Status Message Macros" collapsible=true
```rust
match some_func(x) => {
Ok(_) => {
success!("This worked!");
},
Err(e) => {
failure!("An error occurred: {}", e);
// Handle the error.
}
}
```
````