Formatting conventions and best practices for Sentinel codebase.
Formatting
rustfmt
All code must be formatted with rustfmt:
# Format all code
# Check formatting without changing
Configuration
The project uses default rustfmt settings. If customization is needed, create rustfmt.toml:
= "2021"
= 100
= 4
= "Default"
Linting
Clippy
All code must pass clippy with no warnings:
# Run clippy
# Treat warnings as errors (CI mode)
# With all features
Allowed Lints
Suppress specific lints only with justification:
// Reason: XYZ requires this pattern
Denied Lints
These are always errors:
// No unsafe without review
// Public items need docs
// Must handle Results
Naming Conventions
General Rules
| Item | Convention | Example |
|---|---|---|
| Types | PascalCase | RouteConfig, HttpRequest |
| Functions | snake_case | handle_request, parse_config |
| Variables | snake_case | request_count, upstream_url |
| Constants | SCREAMING_SNAKE_CASE | MAX_CONNECTIONS, DEFAULT_TIMEOUT |
| Modules | snake_case | health_check, route_matching |
| Traits | PascalCase | Handler, Configurable |
| Lifetimes | short lowercase | 'a, 'req, 'cfg |
Prefixes/Suffixes
| Pattern | Usage | Example |
|---|---|---|
is_*, has_* | Boolean functions | is_healthy(), has_body() |
*_mut | Mutable variants | get_config_mut() |
try_* | Fallible operations | try_parse() |
into_* | Consuming conversions | into_response() |
as_* | Borrowed conversions | as_bytes() |
*Builder | Builder types | RequestBuilder |
*Config | Configuration structs | ServerConfig |
*Error | Error types | ConfigError |
Module Organization
// Good: logical grouping
// In each module:
mod.rs or module_name.rs
├── types.rs // Public types
├── error.rs // Module-specific errors
├──
Documentation
Public Items
All public items require documentation:
/// A route configuration entry.
///
/// Routes define how incoming requests are matched and
/// forwarded to upstream services.
///
/// # Examples
///
/// ```
/// let route = Route::new("/api")
/// .upstream("backend")
/// .timeout(Duration::from_secs(30));
/// ```
Functions
/// Parses a KDL configuration file.
///
/// # Arguments
///
/// * `path` - Path to the configuration file
///
/// # Returns
///
/// The parsed configuration or an error if parsing fails.
///
/// # Errors
///
/// Returns `ConfigError::IoError` if the file cannot be read.
/// Returns `ConfigError::ParseError` if the KDL is invalid.
Internal Code
Internal code should be self-documenting with clear names. Add comments for non-obvious logic:
Error Handling
Error Types
Use thiserror for library errors:
use Error;
Error Propagation
Use ? operator and anyhow for applications:
// Library code: explicit error types
// Application code: anyhow for convenience
Avoid Panics
Never panic in library code:
// Bad: panics on invalid input
// Good: returns Option
// Good: returns Result with context
Async Code
Async Functions
// Prefer async fn over manual Future impl
pub async
// Use async blocks for closures
let handler = ;
Cancellation Safety
Document cancellation behavior:
/// Processes a request through the agent pipeline.
///
/// # Cancellation Safety
///
/// This function is cancellation-safe. If cancelled, no partial
/// state will be left. In-flight requests to agents will be
/// abandoned but the connection remains valid.
pub async
Avoid Blocking
Never block in async code:
// Bad: blocks the runtime
async
// Good: use async filesystem
async
// Good: spawn blocking for CPU-heavy work
async
Testing
Test Organization
// Unit tests in the same file
// Integration tests in tests/ directory
// tests/integration_test.rs
Test Naming
Async Tests
async
Performance
Avoid Allocations in Hot Paths
// Bad: allocates on every call
// Good: write to existing buffer
Use Appropriate Collections
// Small fixed set: array
const METHODS: = ;
// Fast lookup: HashMap with ahash
use AHashMap;
let routes: = new;
// Ordered iteration: BTreeMap
use BTreeMap;
let sorted: = new;
Next Steps
- Testing - Testing strategy
- Contributing - Submit changes
- PR Process - Code review