5.6 KiB
5.6 KiB
Coding Conventions
Analysis Date: 2026-02-28
Overview
This is an early-stage Rust project with minimal codebase (single main.rs file). Conventions are established based on:
- Rust language defaults and community standards
- Cargo default behavior
- Current code patterns in the project
Naming Patterns
Files:
- Snake case:
main.rs,lib.rsare standard entry points - Module files use snake_case:
user_service.rs,data_handler.rs - Test modules within files or in separate
tests/directory
Functions:
- Snake case throughout:
fn handle_connection(),fn parse_input() - Use descriptive verb-based names:
fn calculate_sum(),fn build_response()
Variables:
- Snake case for bindings:
let user_id,let response_data - Constants use UPPER_CASE:
const MAX_BUFFER_SIZE: usize = 1024 - Mutable bindings explicitly marked:
let mut count = 0
Types and Structs:
- PascalCase for type names:
struct User,enum Status,trait Handler - Generic parameters use single letters or PascalCase:
T,S,Request - Lifetime parameters use lowercase:
'a,'static
Code Style
Formatting:
- Default Rust formatting applied by
rustfmt(de facto standard) - 4-space indentation (Rust default)
- No semicolons in final expressions that return values
- Closing braces on same line except for block statements
Linting:
- Clippy lints should be addressed as part of development
- No explicit
clippy.tomlor linting configuration currently present - Default clippy warnings and errors should be resolved before commit
Edition:
- Rust 2024 edition (specified in
Cargo.toml) - Supports latest language features and idioms
Import Organization
Order:
- Standard library imports (
use std::) - External crate imports (
use ratatui::, other external deps) - Internal crate imports (
use crate::) - Module declarations (
mod xyz;)
Example:
use std::io;
use std::collections::HashMap;
use ratatui::backend::CrosstermBackend;
use ratatui::Terminal;
use crate::ui::draw;
use crate::handler::InputHandler;
Path Aliases:
- No path aliases configured currently
- Can be added via workspace root configuration if needed
Error Handling
Patterns:
- Use
Result<T, E>for fallible operations - Propagate errors with
?operator rather than unwrapping when possible - Use
anyhow::Resultfor application-level errors (dependency available) - Only use
.unwrap()or.expect()for code that should never panic in normal operation
Example:
fn read_config(path: &str) -> Result<Config> {
let content = std::fs::read_to_string(path)?;
let config = serde_json::from_str(&content)?;
Ok(config)
}
Logging
Framework: Not yet selected/integrated
When logging is added:
- Use
logcrate for production logging - Use
env_loggeror similar for log configuration - Log levels: ERROR for failures, WARN for unusual conditions, INFO for significant events, DEBUG for detailed traces
- Avoid logging sensitive data (credentials, tokens, PII)
Comments
When to Comment:
- Explain the "why" not the "what"
- Document non-obvious algorithmic decisions
- Explain trade-offs or workarounds
- Mark intentional violations of conventions with
// FIXME:or// TODO:
Doc Comments:
- Use
///for public item documentation - Document public functions, structs, enums, traits
- Include examples for complex or non-obvious public APIs
Example:
/// Processes a user command from the input buffer.
///
/// This function parses the raw input and dispatches to appropriate handlers.
///
/// # Arguments
/// * `input` - Raw user input string
///
/// # Returns
/// `Result<CommandResult, Error>` indicating success or the error encountered
pub fn process_command(input: &str) -> Result<CommandResult> {
// Implementation
}
Function Design
Size:
- Keep functions small and focused (ideally < 50 lines)
- Extract helper functions for complex logic
- Separate parsing, validation, and execution logic
Parameters:
- Use owned values for simple types, references for larger types
- Prefer
&[T]over&Vec<T>for function parameters - Use structs to group related parameters (> 3 related params)
Return Values:
- Use
Result<T, E>for operations that can fail - Use
Option<T>for values that may be absent - Avoid returning
Box<dyn Trait>unless necessary for dynamic dispatch
Module Design
Exports:
- Explicitly declare public items with
pub - Use
pub useto re-export important types at module boundaries - Keep implementation details private (
non-pubby default)
Module Structure:
// src/main.rs
mod ui;
mod handler;
mod model;
use ui::App;
use handler::InputHandler;
fn main() {
// Implementation
}
Barrel Files:
- Use
mod.rsfiles in subdirectories to organize module exports - Example:
src/ui/mod.rsexports types fromui/draw.rs,ui/state.rs
Unsafe Code
Usage:
- Avoid unsafe blocks unless necessary for FFI or performance-critical code
- Document unsafe code with
// SAFETY:comments explaining invariants - Minimize unsafe scope
Example:
// SAFETY: ptr is guaranteed to point to valid, initialized memory
// returned from foreign_function, which owns its lifetime
unsafe {
let result = process_data(ptr);
}
Workspace and Multi-Crate Structure
Currently: Single binary crate (bbs-md)
If expanding:
- Consider separating into
bbs-md(binary) andbbs-md-core(library) - Use workspace for shared dependencies and configuration
- Place library code in
src/lib.rs, binary-specific code insrc/main.rs
Convention analysis: 2026-02-28