2019-12-09 15:41:19 +01:00
|
|
|
# Code style
|
2022-09-29 17:01:03 +02:00
|
|
|
|
|
|
|
This is a description of a coding style that every contributor must follow.
|
|
|
|
Please, read the whole document before you start pushing code.
|
2019-12-09 15:41:19 +01:00
|
|
|
|
|
|
|
## Generics
|
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
All trait bounds should be written in `where`
|
2019-12-09 15:41:19 +01:00
|
|
|
|
|
|
|
```rust
|
2022-09-29 17:01:03 +02:00
|
|
|
// 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>>
|
2019-12-09 15:41:19 +01:00
|
|
|
(user_id: i32, name: N, title: T, png_sticker: P, emojis: E) -> Self { ... }
|
|
|
|
```
|
2022-09-29 17:01:03 +02:00
|
|
|
```rust
|
|
|
|
// GOOD
|
|
|
|
impl<T> Trait for Wrap<T>
|
|
|
|
where
|
|
|
|
T: Trait
|
|
|
|
{ ... }
|
|
|
|
|
|
|
|
// BAD
|
|
|
|
impl<T: Trait> Trait for Wrap<T> { ... }
|
|
|
|
```
|
2019-12-09 15:41:19 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
**Rationale:** `where` clauses are easier to read when there are a lot of bounds, uniformity.
|
|
|
|
|
|
|
|
## Documentation comments
|
|
|
|
|
|
|
|
1. Documentation must describe what your code does and mustn't describe how your code does it and bla-bla-bla.
|
|
|
|
2. Be sure that your comments follow the grammar, including punctuation, the first capital letter and so on.
|
|
|
|
```rust
|
|
|
|
// GOOD
|
|
|
|
/// This function makes a request to Telegram.
|
|
|
|
pub fn make_request(url: &str) -> String { ... }
|
|
|
|
|
|
|
|
// BAD
|
|
|
|
/// this function make request to telegram
|
|
|
|
pub fn make_request(url: &str) -> String { ... }
|
|
|
|
```
|
|
|
|
3. Do not use ending punctuation in short list items (usually containing just one phrase or sentence).
|
|
|
|
```md
|
|
|
|
<!-- GOOD -->
|
|
|
|
- Handle different kinds of Update
|
|
|
|
- Pass dependencies to handlers
|
|
|
|
- Disable a default Ctrl-C handling
|
|
|
|
|
|
|
|
<!-- BAD -->
|
|
|
|
- Handle different kinds of Update.
|
|
|
|
- Pass dependencies to handlers.
|
|
|
|
- Disable a default Ctrl-C handling.
|
|
|
|
|
|
|
|
<!-- BAD -->
|
|
|
|
- Handle different kinds of Update;
|
|
|
|
- Pass dependencies to handlers;
|
|
|
|
- Disable a default Ctrl-C handling;
|
|
|
|
```
|
|
|
|
3. Link resources in your comments when possible, for example:
|
|
|
|
```rust
|
|
|
|
/// Download a file from Telegram.
|
|
|
|
///
|
|
|
|
/// `path` can be obtained from the [`Bot::get_file`].
|
|
|
|
///
|
|
|
|
/// To download into [`AsyncWrite`] (e.g. [`tokio::fs::File`]), see
|
|
|
|
/// [`Bot::download_file`].
|
|
|
|
///
|
|
|
|
/// [`Bot::get_file`]: crate::bot::Bot::get_file
|
|
|
|
/// [`AsyncWrite`]: tokio::io::AsyncWrite
|
|
|
|
/// [`tokio::fs::File`]: tokio::fs::File
|
|
|
|
/// [`Bot::download_file`]: crate::Bot::download_file
|
|
|
|
```
|
|
|
|
|
|
|
|
## Use `Self` where possible
|
|
|
|
|
|
|
|
When referring to the type for which block is implemented, prefer using `Self`, rather than the name of the type.
|
2019-12-09 15:41:19 +01:00
|
|
|
|
|
|
|
```rust
|
2022-09-29 17:01:03 +02:00
|
|
|
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>
|
2019-12-09 15:41:19 +01:00
|
|
|
where
|
2022-09-29 17:01:03 +02:00
|
|
|
C: Into<String>,
|
|
|
|
{ ... }
|
|
|
|
}
|
2019-12-09 15:41:19 +01:00
|
|
|
```
|
2020-01-08 11:20:20 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
**Rationale:** `Self` is generally shorter and it's easier to copy-paste code or rename the type.
|
2020-01-08 11:20:20 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
## Avoid duplication in fields names
|
2020-01-08 11:20:20 +01:00
|
|
|
|
|
|
|
```rust
|
2022-09-29 17:01:03 +02:00
|
|
|
struct Message {
|
|
|
|
// GOOD
|
|
|
|
#[serde(rename = "message_id")]
|
|
|
|
id: MessageId,
|
|
|
|
|
|
|
|
// BAD
|
|
|
|
message_id: MessageId,
|
|
|
|
}
|
2020-01-08 11:20:20 +01:00
|
|
|
```
|
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
**Rationale:** duplication is unnecessary
|
2020-01-08 11:20:20 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
## Conventional generic names
|
2020-01-08 15:46:09 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
Use a generic parameter name `S` for streams, `Fut` for futures, `F` for functions (where possible).
|
2022-08-20 12:16:08 +02:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
**Rationale:** uniformity.
|
2022-08-20 12:16:08 +02:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
## Deriving traits
|
2022-08-20 12:16:08 +02:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
Derive `Copy`, `Clone`, `Eq`, `PartialEq`, `Hash` and `Debug` for public types when possible.
|
2022-08-20 12:16:08 +02:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
**Rationale:** these traits can be useful for users and can be implemented for most types.
|
2022-08-20 12:16:08 +02:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
Derive `Default` when there is a reasonable default value for the type.
|
2022-08-20 12:16:08 +02:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
**Rationale:** `Default` plays nicely with generic code (for example `mem::take`).
|
2020-01-24 23:29:55 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
## `Into`-polymorphism
|
2020-01-24 23:29:55 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
Use `T: Into<Ty>` when this can simplify user code.
|
|
|
|
I.e. when there are types that implement `Into<Ty>` that are likely to be passed to this function.
|
2020-01-08 15:46:09 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
**Rationale:** conversions unnecessarily complicate caller code and can be confusing for beginners.
|
|
|
|
|
|
|
|
## `must_use`
|
|
|
|
|
|
|
|
Always mark a functions as `#[must_use]` if they don't have side-effects and the only reason to call them is to get the result.
|
2020-01-08 15:46:09 +01:00
|
|
|
|
|
|
|
```rust
|
2022-09-29 17:01:03 +02:00
|
|
|
impl User {
|
|
|
|
// GOOD
|
|
|
|
#[must_use]
|
|
|
|
fn full_name(&self) -> String {
|
|
|
|
format!("{} {}", user.first_name, user.last_name)
|
2020-01-08 15:46:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
**Rationale:** users will get warnings if they forgot to do something with the result, potentially preventing bugs.
|
|
|
|
|
|
|
|
## Creating boxed futures
|
|
|
|
|
|
|
|
Prefer `Box::pin(async { ... })` instead of `async { ... }.boxed()`.
|
|
|
|
|
|
|
|
**Rationale:** the former is generally formatted better by rustfmt.
|
|
|
|
|
|
|
|
## Full paths for logging
|
|
|
|
|
|
|
|
Always write `log::<op>!(...)` instead of importing `use log::<op>;` and invoking `<op>!(...)`.
|
2020-01-08 15:46:09 +01:00
|
|
|
|
|
|
|
```rust
|
2022-09-29 17:01:03 +02:00
|
|
|
// GOOD
|
|
|
|
log::warn!("Everything is on fire");
|
2020-01-24 23:47:47 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
// BAD
|
|
|
|
use log::warn;
|
2020-01-24 23:59:37 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
warn!("Everything is on fire");
|
|
|
|
```
|
2020-01-24 23:59:37 +01:00
|
|
|
|
2022-09-29 17:01:03 +02:00
|
|
|
**Rationale:** uniformity, it's clearer which log crate is used.
|
2022-09-29 17:05:31 +02:00
|
|
|
|
|
|
|
## `&str` -> `String` conversion
|
|
|
|
|
|
|
|
Prefer using `.to_owned()`, rather than `.to_string()`, `.into()`, `String::from`, etc.
|
|
|
|
|
|
|
|
**Rationale:** uniformity, intent clarity.
|