Code Style and Conventions
Formatting
Use cargo fmt with the default rustfmt configuration:
cargo fmt
CI enforces formatting with cargo fmt --all -- --check.
Linting
All clippy warnings are treated as errors:
cargo clippy -- -D warnings
This is enforced in CI. Fix all warnings before submitting a PR.
Quick Check
The Makefile runs both:
make check
# Equivalent to: cargo fmt && cargo check && cargo clippy -- -D warnings
Module Structure Conventions
File Naming
- Simple modules:
src/modules/my_module.rs - Complex modules with sub-parts:
src/modules/my_module/mod.rs+ sub-files - Services follow the same pattern:
src/services/my_service.rsorsrc/services/my_service/mod.rs
Message Enums
Every module defines its own Message enum:
#![allow(unused)]
fn main() {
#[derive(Debug, Clone)]
pub enum Message {
// Module-specific variants
}
}
Action Pattern
Modules that need to communicate side effects to the App use an Action enum:
#![allow(unused)]
fn main() {
pub enum Action {
None,
Command(Task<Message>),
CloseMenu,
// ...
}
}
Constructor Convention
Modules take their config in new():
#![allow(unused)]
fn main() {
pub fn new(config: MyModuleConfig) -> Self { /* ... */ }
}
Logging
Use the log crate macros:
#![allow(unused)]
fn main() {
use log::{debug, info, warn, error};
debug!("Detailed debugging info");
info!("Notable events");
warn!("Something unexpected but recoverable");
error!("Something went wrong");
}
Avoid println! β all output should go through the logger so itβs captured in log files.
Error Handling
- Services use
anyhowor custom error types - Config parsing uses
Box<dyn Error> - Prefer logging errors over panicking in service code
- Use
unwrap_or_default()orunwrap_or_else()for recoverable cases
Imports
- Group imports by crate (std, external, internal)
- Use
crate::prefix for internal imports - Prefer specific imports over glob imports