Code style
Code conventions in Xindeler. 90% is applied automatically by tooling β you don't need to memorize it.
Required toolsβ
rustfmtβ
Formats code automatically. There's no debate about formatting style β rustfmt has the final word.
cargo fmt
Configuration lives in rustfmt.toml at the repo root. Run cargo fmt before every commit.
clippyβ
Rust's linter. Detects problematic patterns, inefficient code, and common mistakes.
cargo clippy -- -D warnings
The -D warnings flag treats warnings as errors β this is what CI runs. Your code must pass with no warnings before opening a PR.
Some useful lints clippy catches in this project:
// β clippy::clone_on_copy
let x = some_u32.clone(); // u32 implements Copy, .clone() is unnecessary
// β
let x = some_u32;
// β clippy::needless_pass_by_value
fn process(items: Vec<Item>) { ... } // if you don't need ownership
// β
fn process(items: &[Item]) { ... }
Naming conventionsβ
Rust has strong conventions, and the compiler warns when they aren't followed:
| Element | Convention | Example |
|---|---|---|
| Types, traits, enums | UpperCamelCase | HealthComponent, CombatSystem |
| Functions, methods, variables | snake_case | apply_damage, max_health |
| Constants | SCREAMING_SNAKE_CASE | MAX_PLAYERS, BASE_DAMAGE |
| Modules, crates | snake_case | combat_sys, rtsim |
| Files | snake_case | combat_sys.rs, npc_mind.rs |
Naming in this projectβ
A few conventions specific to this codebase:
- ECS systems end in
_sysorSystem:CombatSystem,ai_sys.rs - ECS components end in
Compor are simple nouns:Health,Energy,Pos - RON files use the asset's name in
snake_case:iron_sword.ron - Server events use
ServerEvent::Variante
Commentsβ
Write comments only when the why isn't obvious. The what is already stated by the code.
// β adds nothing
// Increment the kill counter
player.kills += 1;
// β
explains a non-obvious decision
// We use saturating_add to avoid overflow in long-session counters
player.kills = player.kills.saturating_add(1);
For public functions in common/, doc comments (///) with a one-line description are expected:
/// Returns the effective damage after applying armor mitigation.
pub fn mitigate_damage(raw: f32, armor: f32) -> f32 {
raw * (1.0 - armor.min(0.9))
}
Error handlingβ
- Use
?to propagate errors instead of.unwrap()in production code .unwrap()and.expect()are allowed in tests and in situations where the invariant is impossible to violate (document it with a comment)- Prefer
Optionover sentinel values (-1,"", etc.)
// β panics in production
let item = inventory.get(slot).unwrap();
// β
let Some(item) = inventory.get(slot) else {
return; // empty slot, nothing to do
};
Performanceβ
- Avoid allocations in ECS systems that run every tick β use slices and references where possible
- Prefer
&stroverStringin function parameters - Parallel
specssystems must not contain aMutexβ parallelism is managed by the ECS scheduler - Profile before optimizing:
cargo flamegraphorperfon Linux