# Rust Application Development Guidelines **Document Version:** v1 > **Note on Versioning:** > - This document version is independent — reused across projects > - **Project version** source of truth: `Cargo.toml` under `[package]` > - `CHANGELOG.md` uses project version from `Cargo.toml` ## Related Documents - **README.md** — Project overview, build instructions, usage - **AGENTS.md** — Rules for AI assistants - **PROJECT.md** — Project goals and current state - **CHANGELOG.md** — Version history --- ## 1. Code Style - **Rust edition:** 2021 - Format with **rustfmt** — run `cargo fmt` before every commit - Lint with **clippy** — run `cargo clippy -- -D warnings` before every commit - **snake_case** functions/variables/modules, **PascalCase** types/traits, **SCREAMING_SNAKE_CASE** constants - Keep functions short and focused — one responsibility per function --- ## 2. Cargo ```bash cargo add # Add runtime dependency cargo add --dev # Add dev dependency cargo remove # Remove dependency cargo build # Debug build cargo build --release # Release build cargo run # Run debug build cargo run --release # Run release build cargo test # Run all tests cargo fmt # Format code cargo clippy -- -D warnings # Lint (treat warnings as errors) ``` Never edit `Cargo.toml` dependency versions by hand — use `cargo add`. --- ## 3. Project Structure ``` project/ ├── src/ │ ├── main.rs # Entry point │ ├── lib.rs # Optional: shared library code │ └── / │ └── mod.rs ├── tests/ # Integration tests ├── Cargo.toml └── Cargo.lock # Commit for applications, not for libraries ``` A project may have multiple binaries under `src/bin/`. --- ## 4. Error Handling - Use **thiserror** for defining typed errors in library/domain code - Use **anyhow** for application-level error propagation (`main`, CLI handlers) - Never use `.unwrap()` in production code — use `?` or explicit handling - `.expect("reason")` is acceptable only when the invariant is guaranteed and documented --- ## 5. Logging Use **tracing** for structured logging. ```toml [dependencies] tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } ``` ```rust use tracing::{debug, info, warn, error}; fn main() { tracing_subscriber::fmt() .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) .init(); } ``` Control log level via `RUST_LOG` environment variable: ```bash RUST_LOG=debug cargo run RUST_LOG=my_app=info,warn cargo run ``` #### Log levels | Level | When to use | |-------|-------------| | `debug` | Per-item detail: internal state, cache hits, per-item operations | | `info` | User-visible milestones: process started/finished, file saved | | `warn` | Recoverable issues: fallback used, unexpected but non-fatal state | | `error` | Failures the user must know about — operation cannot continue | Never use `println!` for debugging or internal logging. --- ## 6. Environment and Secrets - Store secrets in `.env` file - Load via **dotenvy** crate and `std::env::var()` - Never commit `.env` ```rust dotenvy::dotenv().ok(); let api_key = std::env::var("API_KEY").expect("API_KEY must be set"); ``` --- ## 7. Testing - Use Rust's built-in test framework — `#[test]` and `#[cfg(test)]` - Unit tests live in the same file as the code, in a `mod tests` block - Integration tests live in `tests/` - Use `assert_eq!`, `assert!`, `assert_ne!` — no external test frameworks needed - Test naming: `test__` ```rust #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_valid_input() { assert_eq!(parse("42"), Ok(42)); } } ``` --- ## 8. Tooling | Tool | Purpose | |------|---------| | **rustfmt** | Code formatting | | **clippy** | Linting | | **cargo test** | Testing | | **cargo build --release** | Production build | Run before every commit: ```bash cargo fmt cargo clippy -- -D warnings cargo test ``` --- ## 9. Distribution For standalone executables: ```bash cargo build --release # Binary is at: target/release/ ``` For cross-compilation (e.g. Windows from Linux): ```bash cargo install cross cross build --release --target x86_64-pc-windows-gnu ``` `Cargo.lock` **is committed** for applications — it ensures reproducible builds. --- ## 10. Versioning - Follow **semantic versioning**: `MAJOR.MINOR.PATCH` - Version is defined in `Cargo.toml` under `[package]` - Always ask before bumping the version — never increment automatically - Update `CHANGELOG.md` before bumping the version --- ## 11. Documentation and Task Management - Keep `PROJECT.md` and `CHANGELOG.md` up to date when making changes ### Task notation ```rust // TODO: one-liner description of a task to be done // FIXME: one-liner description of a known bug to be fixed ```