# 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(user_id: i32, name: N, title: T, png_sticker: P, emojis: E) -> Self where N: Into, T: Into, P: Into, E: Into, { ... } // BAD pub fn new, T: Into, P: Into, E: Into> (user_id: i32, name: N, title: T, png_sticker: P, emojis: E) -> Self { ... } ``` ```rust // GOOD impl Trait for Wrap where T: Trait { ... } // BAD impl Trait for Wrap { ... } ``` **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 - Handle different kinds of Update - Pass dependencies to handlers - Disable a default Ctrl-C handling - Handle different kinds of Update. - Pass dependencies to handlers. - Disable a default Ctrl-C handling. - 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. ```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(bot: &'a Bot, callback_query_id: C) -> Self where C: Into, { ... } // BAD fn new(bot: &'a Bot, callback_query_id: C) -> AnswerCallbackQuery<'a> where C: Into, { ... } } ``` **Rationale:** `Self` is generally shorter and it's easier to copy-paste code or rename the type. ## Avoid duplication in fields names ```rust struct Message { // GOOD #[serde(rename = "message_id")] id: MessageId, // BAD message_id: MessageId, } ``` **Rationale:** duplication is unnecessary ## Conventional generic names Use a generic parameter name `S` for streams, `Fut` for futures, `F` for functions (where possible). **Rationale:** uniformity. ## Deriving traits Derive `Copy`, `Clone`, `Eq`, `PartialEq`, `Hash` and `Debug` for public types when possible. **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. **Rationale:** `Default` plays nicely with generic code (for example `mem::take`). ## `Into`-polymorphism Use `T: Into` when this can simplify user code. I.e. when there are types that implement `Into` that are likely to be passed to this function. **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. ```rust impl User { // GOOD #[must_use] fn full_name(&self) -> String { format!("{} {}", user.first_name, user.last_name) } } ``` **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::!(...)` instead of importing `use log::;` and invoking `!(...)`. ```rust // GOOD log::warn!("Everything is on fire"); // BAD use log::warn; warn!("Everything is on fire"); ``` **Rationale:** uniformity, it's clearer which log crate is used.