Skip to content

Latest commit

 

History

History
258 lines (184 loc) · 6.24 KB

CONTRIBUTING.md

File metadata and controls

258 lines (184 loc) · 6.24 KB

Contribution Guide

🎈 Thanks for your help improving the project! We are so happy to have you!

No contribution is too small and all contributions are valued.

  1. Code style

Code style

All Rust source code must be formatted with rustfmt and linted with Clippy linter, customized by project settings (.rustfmt.toml and .clippy.toml files).

Additional rules, not handled by rustfmt and Clippy are described below.

Imports, re-exports and modules declarations

These should be divided into the following ordered sections:

  1. modules declarations (mod and pub mode keywords);
  2. imports sections (use keyword):
    1. std/core imports;
    2. external crates imports;
    3. this crate imports (start with crate::);
    4. imports from parent modules (start with super::);
    5. imports from sub-modules (start with self::).
  3. re-export sections (pub use keyword):
    1. std/core re-exports;
    2. external crates re-exports;
    3. this crate re-exports (start with crate::);
    4. re-exports from parent modules (start with super::);
    5. re-exports from sub-modules (start with self::).

A blank line is mandatory between these sections, before and after.

Items must be sorted in alphabetical order inside each section and inside each statement.

If imported trait is not used directly, then it must be underscore imported (as _) to not pollute the current module's namespace.

Import multiple items in one statement from one location, rather than using multiple statements (usually, controlled by merge_imports option of rustfmt).

👍 Correct example

//! Some module.

mod private_stuff;
pub mod public_stuff;

use std::sync::{Arc, Mutex};

use chrono::{DateTime, Utc};
use futures::Future as _;
use serde::{Deserialize, Serialize};

use crate::core::{DynFuture, DynStream};

use super::event;

use self::private_stuff::util;

pub use postgres::Type;

pub use crate::core::util::UnfoldingStream;

pub use super::props::Error;

pub use self::public_stuff::*;

const LIMIT: u8 = 100;

🚫 Wrong examples

  • No blank lines:

    //! Some module.
    mod private_stuff;
    pub mod public_stuff;
    use std::sync::{Arc, Mutex};
    use chrono::{DateTime, Utc};
    use futures::Future as _;
    use serde::{Deserialize, Serialize};
    use crate::core::{DynFuture, DynStream};
    use super::event;
    use self::private_stuff::util;
    pub use postgres::Type;
    pub use crate::core::util::UnfoldingStream;
    pub use super::props::Error;
    pub use self::public_stuff::*;
    use std::sync::{Arc, Mutex};
    use chrono::{DateTime, Utc};
    use futures::Future as _;
    use serde::{Deserialize, Serialize};
    
    use crate::core::{DynFuture, DynStream};
    use super::event;
    use self::private_stuff::util;
    
    pub use postgres::Type;
    pub use crate::core::util::UnfoldingStream;
    pub use super::props::Error;
    pub use self::public_stuff::*;
    pub use self::public_stuff::*;
    const LIMIT: u8 = 100;
  • Not sorted alphabetically:

    use serde::{Serialize, Deserialize};
    pub mod public_stuff;
    mod private_stuff;
    
    use futures::Future as _;
    use serde::{Deserialize, Serialize};
    use chrono::{DateTime, Utc};
  • Multiple statements for items from the same location:

    use chrono::DateTime;
    use chrono::Utc;
    use serde::Deserialize;
    use serde::Serialize;
  • Imported traits implementations without underscore:

    use futures::{Future, IntoFuture};
    
    use crate::core::DynFuture;
    
    fn do_something() -> DynFuture<i32, ()> {
        Box::new(Ok(21).into_future().map(|n| n + 1))
    }

Attributes

Attributes on declarations must be sorted in alphabetic order. Items inside attribute must be sorted in alphabetic order too (in the same manner they're sorted by rustfmt inside use statement).

👍 Correct example

#[allow(clippy::mut_mut)]
#[derive(smart_default::SmartDefault, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
struct User {
    #[serde(default)]
    id: u64,
}

🚫 Wrong examples

#[serde(deny_unknown_fields)]
#[derive(smart_default::SmartDefault, Debug, Deserialize, Serialize)]
#[allow(clippy::mut_mut)]
struct User {
    id: u64,
}
#[derive(Debug, smart_default::SmartDefault, Serialize, Deserialize)]
struct User {
    id: u64,
}

Markdown in docs

It's recommended to use H1 headers (# Header) in Rust docs as this way is widely adopted in Rust community. Blank lines before headers must be reduced to a single one.

Bold and italic text should be marked via ** and _ accordingly.

Other code definitions should be referred via [`Entity`] marking (intra-doc links).

👍 Correct example

/// Type of [`User`]'s unique identifier.
/// 
/// # Constraints
/// 
/// - It **must not be zero**.
/// - It _should not_ overflow [`i64::MAX`] due to usage in database.
struct UserId(u64);

🚫 Wrong examples

  • H2 header is used at the topmost level:

    /// Type of [`User`]'s unique identifier.
    /// 
    /// ## Constraints
    /// 
    /// - It **must not be zero**.
    /// - It _should not_ overflow [`i64::MAX`] due to usage in database.
    struct UserId(u64);
  • Code definition is not referred correctly:

    /// Type of User's unique identifier.
    /// 
    /// # Constraints
    /// 
    /// - It **must not be zero**.
    /// - It _should not_ overflow `i64::MAX` due to usage in database.
    struct UserId(u64);
  • Incorrect bold/italic marking:

    /// Type of [`User`]'s unique identifier.
    /// 
    /// # Constraints
    /// 
    /// - It __must not be zero__.
    /// - It *should not* overflow [`i64::MAX`] due to usage in database.
    struct UserId(u64);