Files
cdk/CODE_STYLE.md
thesimplekid 4c2cb78327 chore: update CODE_STYLE
Co-authored-by: Yuki Kishimoto <yukikishimoto@protonmail.com>
2024-04-10 20:49:35 +01:00

237 lines
4.3 KiB
Markdown

# Code style
This is a description of a coding style that every contributor **must** follow.
Please, read the whole document before you start pushing code.
## Generics
All trait bounds should be written in `where`:
```rust
// GOOD
pub fn new<N, T, P, E>(user_id: i32, name: N, title: T, png_sticker: P, emojis: E) -> Self
where
N: Into<String>,
T: Into<String>,
P: Into<InputFile>,
E: Into<String>,
{ ... }
// BAD
pub fn new<N: Into<String>,
T: Into<String>,
P: Into<InputFile>,
E: Into<String>>
(user_id: i32, name: N, title: T, png_sticker: P, emojis: E) -> Self { ... }
```
```rust
// GOOD
impl<T> Trait for Wrap<T>
where
T: Trait
{ ... }
// BAD
impl<T: Trait> Trait for Wrap<T> { ... }
```
## Use `Self` where possible
When referring to the type for which block is implemented, prefer using `Self`, rather than the name of the type:
```rust
impl ErrorKind {
// GOOD
fn print(&self) {
Self::Io => println!("Io"),
Self::Network => println!("Network"),
Self::Json => println!("Json"),
}
// BAD
fn print(&self) {
ErrorKind::Io => println!("Io"),
ErrorKind::Network => println!("Network"),
ErrorKind::Json => println!("Json"),
}
}
```
```rust
impl<'a> AnswerCallbackQuery<'a> {
// GOOD
fn new<C>(bot: &'a Bot, callback_query_id: C) -> Self
where
C: Into<String>,
{ ... }
// BAD
fn new<C>(bot: &'a Bot, callback_query_id: C) -> AnswerCallbackQuery<'a>
where
C: Into<String>,
{ ... }
}
```
**Rationale:** `Self` is generally shorter and it's easier to copy-paste code or rename the type.
## Deriving traits (apply only to libraries)
Derive `Debug`, `Clone`, `Copy`, `PartialEq`, `Eq` and `Hash` for public types when possible (in this order).
**Rationale:** these traits can be useful for users and can be implemented for most types.
Derive `Default` when there is a reasonable default value for the type.
## Full paths for logging
Always write `tracing::<op>!(...)` instead of importing `use tracing::<op>;` and invoking `<op>!(...)`.
```rust
// GOOD
tracing::warn!("Everything is on fire");
// BAD
use tracing::warn;
warn!("Everything is on fire");
```
**Rationale:**
- Less polluted import blocks
- Uniformity
## `&str` -> `String` conversion
Prefer using `.to_string()` or `.to_owned()`, rather than `.into()`, `String::from`, etc.
**Rationale:** uniformity, intent clarity.
## Order of imports
```rust
// First core, alloc and/or std
use core::fmt;
use std::{...};
// Second, external crates (both crates.io crates and other rust-analyzer crates).
use crate_foo::{ ... };
use crate_bar::{ ... };
// If applicable, the current sub-modules
mod x;
mod y;
// Finally, the internal crate modules and submodules
use crate::{};
use super::{};
use self::y::Y;
```
## Import Style
When implementing traits from `core::fmt`/`std::fmt` import the module:
```rust
// GOOD
use core::fmt;
impl fmt::Display for RenameError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { .. }
}
// BAD
impl core::fmt::Display for RenameError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { .. }
}
```
When imports sub-modules:
```rust
// GOOD
mod x;
use self::x::Y;
// BAD
mod x;
use x::Y;
```
## If-let
Avoid the `if let ... { } else { }` construct if possible, use `match` instead:
```rust
// GOOD
match ctx.expected_type.as_ref() {
Some(expected_type) => completion_ty == expected_type && !expected_type.is_unit(),
None => false,
}
// BAD
if let Some(expected_type) = ctx.expected_type.as_ref() {
completion_ty == expected_type && !expected_type.is_unit()
} else {
false
}
```
Use `if let ... { }` when a match arm is intentionally empty:
```rust
// GOOD
if let Some(expected_type) = this.as_ref() {
// Handle it
}
// BAD
match this.as_ref() {
Some(expected_type) => {
// Handle it
},
None => (),
}
```
## Sub-modules
Avoid the `mod x { .. }` construct if possible. Instead, crate a file `x.rs` and define it with `mod x;`
**This applies to all sub-modules except `tests` and `benches`.**
```rust
// GOOD
mod x;
// BAD
mod x {
..
}
```
```rust
// GOOD
#[cfg(test)]
mod tests {
..
}
// BAD
mod tests;
```
```rust
// GOOD
#[cfg(bench)]
mod benches {
..
}
// BAD
mod benches;
```