Skip to content

RAprogramm/RustManifest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rust Code Style Guide

1. Formatting

Important

Format all Rust code using nightly rustfmt.

More information
cargo +nightly fmt --
Why is this important?

Consistent formatting enhances readability, reduces merge conflicts, and makes code reviews smoother. It ensures that every team member’s code adheres to a unified standard.

Examples & Further Explanation

For instance, a well-formatted codebase allows new team members to quickly understand the project structure and logic. Automated formatting saves time and minimizes stylistic debates during code reviews.

1.1 .rustfmt.toml Configuration

Tip

Use the following .rustfmt.toml configuration to ensure consistent formatting across the project.

Configuration
# Do not add trailing commas if there is only one element
trailing_comma = "Never"

# Keep braces on the same line where possible
brace_style = "SameLineWhere"

# Align struct fields if their length is below the threshold
struct_field_align_threshold = 20

# Format comments inside documentation
wrap_comments = true
format_code_in_doc_comments = true

# Do not collapse struct literals into a single line
struct_lit_single_line = false

# Maximum line width
max_width = 99

# Grouping imports
imports_granularity = "Crate"          # Group imports by crate
group_imports = "StdExternalCrate"     # Separate groups: std, external crates, local
reorder_imports = true                 # Sort imports within groups

# Enable unstable features (nightly only)
unstable_features = true
Why is this important?

This configuration enforces clarity and consistency. It reduces unnecessary diffs in pull requests, makes code reviews easier, and ensures that both style and readability remain predictable across the team.

Examples & Further Explanation

Example without configuration

use std::fmt; use std::io; use serde::Serialize;

struct Person {name:String,age:u32}

impl Person{
    pub fn new(name:String,age:u32)->Self{
        Self{name,age}
    }
}

Example with configuration

use std::{fmt, io};

use serde::Serialize;

struct Person {
    name: String,
    age:  u32,
}

impl Person {
    pub fn new(name: String, age: u32) -> Self {
        Self {
            name,
            age,
        }
    }
}

Notice how the imports are grouped and sorted, struct fields are aligned for readability, and braces are consistently placed on the same line. This reduces noise in diffs and makes the codebase approachable for both newcomers and experienced contributors.

2. Naming Conventions

Important

Use clear, descriptive names that reflect purpose. Follow snake_case for variables/functions, PascalCase for types, and SCREAMING_SNAKE_CASE for constants.

More information
  • Descriptive Names:

    • create_user_handler – OK
    • create_user_service – OK
    • create – NO
    • create_user – NO
  • Follow Rust's snake_case for variables and functions.

  • Use PascalCase for structs and enums (e.g., TransactionStatus).

  • Constants should be in SCREAMING_SNAKE_CASE.

Why Descriptive Naming?

Descriptive names reduce ambiguity, facilitate easier onboarding, and improve maintainability. Clear names make it evident what a function or variable does, avoiding misunderstandings and conflicts.

Examples & Further Explanation

For example, create_user_handler indicates that the function is responsible for handling user creation in a web context, whereas a generic name like create gives no context.

3. Code Quality

Important

Write clean, maintainable code. Avoid unnecessary complexity, panics, and cloning. Minimize global state and restrict use of :: to import statements. Do not use mod.rs files.

More information
  • Write clean and maintainable code.
  • Avoid unnecessary complexity.
  • Avoid unnecessary unwrap() and clone().
  • Minimize global state and side effects.
  • Use :: only in import statements.
  • Do not use mod.rs files.
Examples & Further Explanation

Instead of writing some_option.unwrap(), prefer:

let value = some_option.ok_or("Expected a value, but found None")?;

This propagates errors properly and avoids crashing the application. Similarly, favor organizing modules in separate module_name.rs files rather than using legacy mod.rs files, which simplifies project structure and improves module discoverability.

4. Branch Management

Note

Each branch, commit, and PR must correspond directly to a GitHub Issue number. This ensures automatic linking, clean history, and full traceability.

More information
  • Create a Branch Named Only by Issue Number:
    Each branch name must be exactly the Issue number.
    Example:

    git checkout -b 123
  • Use Auto-Linking in Commits:
    To make GitHub automatically link commits to Issues, always start the commit message with # followed by the Issue number and a space.
    Example:

    #123 implement login session restore  
    #123 fix null pointer in user handler
  • Pull Request Title = Branch Name:
    The PR title must be the same as the branch name (just the Issue number).
    Example:

    123
    
  • Add an Auto-Close Reference:
    In the PR description, always include:

    Closes #123
    

    This automatically closes the Issue when the PR is merged.

  • Clean Up After Merge:
    Enable “Delete branch on merge” in repository settings, so merged branches are automatically removed.
    The chain Issue → Branch → Commits → PR → Merge remains fully linked.

  • Keep the Repository Clean:
    Every branch must correspond to an active Issue.
    No orphaned or experimental branches should remain after merge.

Real-World Example & Explanation

Suppose you are assigned Issue #123 to fix a login session bug. You create a branch named 123 and start committing with messages like:

  #123 implement login session restore  
  #123 add retry logic for session token refresh  
  

Then you open a PR titled 123 with the description:

  Closes #123
  

When the PR is merged, GitHub automatically closes Issue #123, deletes the branch, and shows all related commits in the Issue timeline. This creates a perfectly traceable and automated workflow with minimal manual steps.

5. Best Practices

Tip

Follow best practices to maintain high code quality.

More information
  • Use cargo clippy for linting.
  • Handle errors gracefully using Result and Option.
  • Avoid unnecessary panics.
Examples & Further Explanation

Instead of writing:

let value = some_option.unwrap();

use:

let value = some_option.ok_or("Expected a value, but found None")?;

This pattern ensures errors are propagated and handled appropriately, increasing the robustness of your application.

6. Panics in Rust

Important

Avoid panics in production; use proper error handling with Result and the ? operator.

More information
  • Avoid panics in production code.
  • Discouraged: Avoid using unwrap() and expect() unless absolutely certain that an error cannot occur.
  • Preferred: Use proper error handling with Result and the ? operator.
Examples & Further Explanation

For example, instead of:

let config = Config::from_file("config.toml").unwrap();

use:

let config = Config::from_file("config.toml")
  .map_err(|e| format!("Failed to load config: {}", e))?;

This approach logs detailed error messages and gracefully propagates errors up the call stack, leading to a more robust and maintainable system.

7. Testing & CI

Important

All commits must pass pre-commit checks. Tests, formatting, linting, and security scans are enforced both locally (via pre-commit hooks) and remotely (via CI).

More information
  • Pre-commit Hooks

    • Installed via:
      cargo make install-hooks
    • Automatically run before each commit:
      cargo +nightly fmt -- 
       cargo clippy -D warnings  
       cargo test --all
    • Prevent committing unformatted code, warnings, or failing tests.
  • Unit Tests

    • Cover public functions and error cases.
    • Tests must not rely on unwrap() or expect().
  • Integration Tests

    • Cover public API, placed in the tests/ directory.
  • Doctests

    • All /// examples must compile and pass with cargo test --doc.
Examples & Further Explanation

Example Unit Test

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_math() {
        assert_eq!(2 + 2, 4);
    }
}

Example Integration Test

// tests/config_tests.rs
use my_crate::load_config;

#[test]
fn load_valid_config() {
    let result = load_config("tests/data/valid.toml");
    assert!(result.is_ok());
}

This workflow enforces correctness at every step: developers cannot commit broken code, and CI ensures nothing slips through at merge time.

8. Code Documentation (No Inline Comments)

Note

No inline code comments. All explanations live in docblocks attached to modules, structs, enums, traits, functions, and methods.

More information
  • No line comments in code:
    Avoid // ... and /* ... */ for explanations of behavior, intent, or invariants. Keep code clean and self-explanatory.

  • Use Rust doc comments consistently:

    • Crate/module: use //! at the top of lib.rs or module files for module-level docs.
    • Items (structs, enums, traits, fns, methods): use /// on the item.
  • Structure docblocks for IDEs and LSPs:
    Use headings Rustdoc understands so hovers and Treesitter outlines are stable and rich:

    • # Overview short purpose
    • # Examples minimal, compilable samples
    • # Errors precise failure modes for Result
    • # Panics only if unavoidable (should be rare)
    • # Safety if unsafe is used (shouldn’t be)
    • # Performance if complexity or allocations matter
  • Write for other engineers:
    Be explicit about contracts, inputs, outputs, invariants, and edge cases. Keep examples runnable. Prefer clarity over cleverness.

  • Keep docs close to code:
    Update docblocks with code changes in the same PR. Out-of-date docs are worse than none.

Correct vs Incorrect (Rust)

Incorrect (inline comments that won’t surface in hovers):

// Calculates checksum and validates header
// Returns Err if invalid
pub fn verify(pkt: &Packet) -> Result<(), VerifyError> {
    // fast path
    if pkt.header.len() < MIN {
        return Err(VerifyError::TooShort);
    }
    // slow path...
    Ok(())
}

Correct (docblocks; IDE hover shows the contract):

/// # Overview
/// Verifies packet header and payload consistency.
///
/// # Examples
/// ```
/// # use mynet::{Packet, verify};
/// # fn demo(mut p: Packet) {
/// #   // prepare p...
/// #   let _ = verify(&p).unwrap();
/// # }
/// ```
///
/// # Errors
/// - `VerifyError::TooShort` when header is smaller than the required minimum.
/// - `VerifyError::ChecksumMismatch` when computed checksum differs.
pub fn verify(pkt: &Packet) -> Result<(), VerifyError> {
    if pkt.header.len() < MIN {
        return Err(VerifyError::TooShort);
    }
    // internal micro-notes for maintainers are allowed if they aid refactoring
    // (but not to explain business logic). Keep them brief.
    Ok(())
}

Module-level docs instead of a comment banner:

//! Cryptographic key management and signing primitives.
//!
//! Provides deterministic ECDSA with explicit domain separation.
//!
//! # Examples
//! ```
//! # use keys::{Keypair, Signer};
//! # fn demo() {
//! #   let kp = Keypair::generate();
//! #   let sig = kp.sign(b"payload");
//! #   assert!(kp.verify(b"payload", &sig).is_ok());
//! # }
//! ```
pub mod crypto { /* ... */ }
Real-World Rationale

This policy ensures stable IDE/LSP hovers, better Treesitter outlines, and reliable navigation. Engineers see contracts immediately, CI can lint docs, and examples stay compilable. Code remains clean while documentation remains discoverable and accurate.

Following these guidelines ensures that our Rust code is high-quality, maintainable, and scalable.

About

Formatting, style, and engineering standards

Topics

Resources

Stars

Watchers

Forks

Sponsor this project

Languages