Write Code
Rust code conventions for Syncpack.
Style
- Functional style: pipelines over loops
- Avoid
? chains: use .and_then(), .map(), .or_else()
- Descriptive names: clarity over brevity
- Named placeholders:
println!("{var}") not println!("{}", var)
- British English: "behaviour" not "behavior", "organised" not "organized"
Imports
Single use statement with grouped braces:
use {
crate::{cli::Cli, config::Config},
log::{debug, error},
std::{process::exit, sync::Arc},
};
Rules:
- Never use
super:: — always crate:: for internal imports
- Group:
crate::, external crates, std::
- Alphabetise within groups
File Organisation
| Adding... |
Location |
| New command |
src/commands/{name}.rs |
| New test |
Sibling _test.rs file (e.g., src/foo.rs → src/foo_test.rs) |
NEVER use #[cfg(test)] modules inside implementation files.
Quality
- Functions <50 lines, commands 100-300 lines
- Zero warnings (except during TDD red phase)
- Run
just format before committing
Comments
Forbidden
//! module docs — collect implementation history and rot
- Phase/F-N labels —
// Phase v4-2, // F16:, banner headers like // ---------- Phase v4-3 RED ----------
- History refs —
Migrated from, carry-over, Mirrors v3, replaces the v3, previously inside X, reserved for future
- Issue/PR refs —
Reproduces issue #239, GitHub issue #206. Plans rot; the code is the truth
- Banner separators —
// ---------- Free functions: yaml ops ----------. Use module structure or let the file speak for itself
- Test scenario labels — don't write
// Windows-style backslashes above a test input. Use a descriptive variable binding (let windows_backslashes = [...]) instead
- Name-restating field docs —
/// A unique identifier for this instance, /// The dependency name, /// The instance id. The field name already says it
- Step numbering inside functions —
// 1. ..., // 2. .... Drop the numbers; keep the WHY if it's non-obvious
Allowed
@TODO markers — future plans worth tracking inline
/// doc comments for non-obvious detail: None/Err semantics, side effects, invariants, distinctions between similar fields (e.g. is_local_dependency vs is_local_instance)
// inline comments when WHY is non-obvious: hidden constraints, ordering invariants ("SnappedTo groups must be visited last"), workarounds for surprising library behaviour, "must not poison X" cautions
Default
No comments. Add one only when the WHY is non-obvious to a fresh reader.
Patterns
Iterating Instances
ctx.version_groups.iter().for_each(|group| {
group.get_sorted_dependencies(&ctx.config.cli.sort).for_each(|dependency| {
dependency.get_sorted_instances()
.filter(|instance| instance.is_invalid())
.for_each(|instance| { /* process */ });
});
});
Error Handling
Prefer combinators over ?:
// Good
path.parent()
.and_then(|p| p.to_str())
.map(|s| s.to_string())
.unwrap_or_default()
// Avoid
let parent = path.parent()?;
let str = parent.to_str()?;
Ok(str.to_string())
State Mutation
let mut state = instance.state.borrow_mut();
if !state.is_invalid() {
*state = InstanceState::fixable(SomeVariant);
}
1---2name: write-code3description: Rust code style and conventions for Syncpack. Use when writing or modifying Rust code. Covers functional patterns, imports, naming, and quality standards.4---56# Write Code78Rust code conventions for Syncpack.910## Style1112- **Functional style:** pipelines over loops13- **Avoid `?` chains:** use `.and_then()`, `.map()`, `.or_else()`14- **Descriptive names:** clarity over brevity15- **Named placeholders:** `println!("{var}")` not `println!("{}", var)`16- **British English:** "behaviour" not "behavior", "organised" not "organized"1718## Imports1920Single `use` statement with grouped braces:2122```rust23use {24 crate::{cli::Cli, config::Config},25 log::{debug, error},26 std::{process::exit, sync::Arc},27};28```2930Rules:3132- **Never use `super::`** — always `crate::` for internal imports33- Group: `crate::`, external crates, `std::`34- Alphabetise within groups3536## File Organisation3738| Adding... | Location |39| ----------- | ---------------------------------------------------------------- |40| New command | `src/commands/{name}.rs` |41| New test | Sibling `_test.rs` file (e.g., `src/foo.rs` → `src/foo_test.rs`) |4243**NEVER** use `#[cfg(test)]` modules inside implementation files.4445## Quality4647- Functions <50 lines, commands 100-300 lines48- Zero warnings (except during TDD red phase)49- Run `just format` before committing5051## Comments5253### Forbidden5455- **`//!` module docs** — collect implementation history and rot56- **Phase/F-N labels** — `// Phase v4-2`, `// F16:`, banner headers like `// ---------- Phase v4-3 RED ----------`57- **History refs** — `Migrated from`, `carry-over`, `Mirrors v3`, `replaces the v3`, `previously inside X`, `reserved for future`58- **Issue/PR refs** — `Reproduces issue #239`, `GitHub issue #206`. Plans rot; the code is the truth59- **Banner separators** — `// ---------- Free functions: yaml ops ----------`. Use module structure or let the file speak for itself60- **Test scenario labels** — don't write `// Windows-style backslashes` above a test input. Use a descriptive variable binding (`let windows_backslashes = [...]`) instead61- **Name-restating field docs** — `/// A unique identifier for this instance`, `/// The dependency name`, `/// The instance id`. The field name already says it62- **Step numbering inside functions** — `// 1. ...`, `// 2. ...`. Drop the numbers; keep the WHY if it's non-obvious6364### Allowed6566- **`@TODO` markers** — future plans worth tracking inline67- **`///` doc comments** for non-obvious detail: `None`/`Err` semantics, side effects, invariants, distinctions between similar fields (e.g. `is_local_dependency` vs `is_local_instance`)68- **`//` inline comments** when WHY is non-obvious: hidden constraints, ordering invariants ("SnappedTo groups must be visited last"), workarounds for surprising library behaviour, "must not poison X" cautions6970### Default7172No comments. Add one only when the WHY is non-obvious to a fresh reader.7374## Patterns7576### Iterating Instances7778```rust79ctx.version_groups.iter().for_each(|group| {80 group.get_sorted_dependencies(&ctx.config.cli.sort).for_each(|dependency| {81 dependency.get_sorted_instances()82 .filter(|instance| instance.is_invalid())83 .for_each(|instance| { /* process */ });84 });85});86```8788### Error Handling8990Prefer combinators over `?`:9192```rust93// Good94path.parent()95 .and_then(|p| p.to_str())96 .map(|s| s.to_string())97 .unwrap_or_default()9899// Avoid100let parent = path.parent()?;101let str = parent.to_str()?;102Ok(str.to_string())103```104105### State Mutation106107```rust108let mut state = instance.state.borrow_mut();109if !state.is_invalid() {110 *state = InstanceState::fixable(SomeVariant);111}112```