Skip to content

Commit 53dfee0

Browse files
authored
Update rust_style_guide.md
Signed-off-by: Xavier Lau <x@acg.box>
1 parent 526d0d1 commit 53dfee0

File tree

1 file changed

+130
-75
lines changed

1 file changed

+130
-75
lines changed

docs/guide/development/rust_style_guide.md

Lines changed: 130 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -3,76 +3,86 @@
33
These rules apply only to Rust code in this repository.
44
All comments and messages must also follow the Global Language Rules in `AGENTS.md`.
55

6-
## Indentation
6+
## Rule Language and Precedence
77

8-
- Use tabs (`\t`) for all indentation.
8+
- MUST indicates a strict requirement.
9+
- SHOULD indicates a strong preference.
10+
- MAY indicates an optional choice.
11+
- rustfmt output is always the final authority for formatting.
912

10-
## Declaration Order
13+
## Normative Rules
1114

12-
Each Rust file must follow this order:
15+
### Indentation
16+
17+
- Indentation MUST use tabs (`\t`).
18+
19+
### Declaration Order
20+
21+
Each Rust file MUST follow this order for module-level items:
1322

1423
```
1524
mod
1625
use
17-
macro_rules
26+
macro_rules!
1827
type
1928
const
29+
static
2030
trait
2131
enum
2232
struct
33+
impl
2334
fn
2435
```
2536

26-
Within each group:
27-
28-
- `pub` items appear before non-`pub`.
29-
30-
Expanded `mod tests` blocks belong at the end of the file, after all other items.
37+
Within each group, `pub` items MUST appear before non-`pub` items.
3138

32-
Inside `mod tests`, prefer `use super::*;` before any other `use` statements.
39+
Expanded `#[cfg(test)] mod tests { ... }` blocks MUST appear at the end of the file, after all other items.
40+
If `mod tests;` is used, it MUST appear after all other items as well.
3341

34-
## Imports and Headers
42+
### Imports and Headers
3543

36-
Allowed `use` section headers:
44+
Allowed `use` section headers are:
3745

38-
- `// std`
39-
- `// crates.io`
40-
- `// self`
46+
- `// std`.
47+
- `// crates.io`.
48+
- `// self`.
4149

4250
Rules:
4351

44-
- Preserve existing header groups.
45-
- Do not invent new groups.
46-
- Do not add headers above non-import definitions.
47-
- If `crate::prelude::*` is imported, avoid redundant imports.
52+
- You MUST preserve existing header groups.
53+
- You MUST NOT invent new groups.
54+
- You MUST NOT add headers above non-import definitions.
55+
- Within each header group, you MUST order imports lexicographically by full path text (ASCII order, case-sensitive).
4856

49-
## Module Layout (No mod.rs)
57+
### Module Layout (No mod.rs)
5058

51-
Use a flat structure:
59+
You MUST use a flat structure:
5260

5361
```
5462
src/foo.rs
5563
src/foo/bar.rs
5664
src/foo/baz.rs
5765
```
5866

59-
Never create or modify `mod.rs`.
67+
You MUST NOT create or modify `mod.rs`.
6068

61-
## Structs, Enums, and Impl Blocks
69+
### Structs, Enums, and Impl Blocks
6270

6371
For each type:
6472

65-
1. The first `impl` block must appear immediately after the type definition.
66-
2. All impls must be contiguous without blank lines between them.
67-
3. Impl order:
68-
1. Inherent impl
69-
2. Std traits
70-
3. Third-party traits
71-
4. Project or self traits
73+
1. The first `impl` block MUST appear immediately after the type definition.
74+
2. All `impl` blocks MUST be contiguous without blank lines between them.
75+
3. `impl` order MUST be:
76+
1. Inherent `impl`.
77+
2. Standard library traits.
78+
3. Third-party traits.
79+
4. Project or self traits.
80+
81+
Inside `impl Type` blocks, you MUST use `Self` instead of the concrete type name when referring to the
82+
implementing type in method signatures (parameters and return types), including references, slices,
83+
and generic containers.
7284

73-
Inside `impl Type` blocks, always use `Self` instead of the concrete type name when referring to
74-
the implementing type in method signatures (parameters and return types), including references,
75-
slices, and generic containers.
85+
Examples (non-normative):
7686

7787
Allowed:
7888

@@ -122,11 +132,11 @@ impl A {
122132
}
123133
```
124134

125-
## Generics and Trait Bounds
135+
### Generics and Trait Bounds
126136

127-
- All bounds go in a `where` clause.
128-
- Inline trait bounds are forbidden.
129-
- Exception: `impl Trait` is always allowed.
137+
- All bounds MUST go in a `where` clause.
138+
- Inline trait bounds MUST NOT be used.
139+
- You MAY use `impl Trait`.
130140

131141
Allowed:
132142

@@ -143,67 +153,112 @@ Forbidden:
143153
fn render<T: Display>(value: T) -> String {
144154
```
145155

146-
## Logging Rules
156+
### Logging Rules
147157

148-
- Never import tracing macros.
149-
- Use fully-qualified macros (`tracing::info!`).
150-
- Prefer named captures:
158+
- Tracing macros MUST be fully qualified (for example, `tracing::info!`).
159+
- Tracing macros MUST NOT be imported.
160+
- Tracing calls MUST use structured fields for dynamic values such as identifiers, names, counts, statuses, sizes, durations, and errors.
161+
- You MUST NOT encode those values only in the message string.
162+
163+
Examples (non-normative):
164+
165+
Allowed:
166+
167+
```rust
168+
tracing::info!(user_id, org_id, "User logged in.");
169+
```
170+
171+
Forbidden:
151172

152173
```rust
153-
tracing::info!("User: {user_id}");
174+
tracing::info!("User {user_id} logged in (org {org_id}).");
154175
```
155176

156-
- Never create temporary variables solely for logging.
177+
### Numeric Literals
178+
179+
- When using a numeric type suffix, you MUST separate the value and suffix with a single underscore.
180+
- For decimal integer literals with more than three digits (ignoring the sign), you MUST insert an underscore every three digits from the right.
181+
182+
Allowed:
183+
184+
- `10_f64`.
185+
- `1_u32`.
186+
- `0_i64`.
187+
- `1_000`.
188+
- `10_000`.
189+
- `1_000_000`.
190+
191+
Forbidden:
192+
193+
- `10f64`.
194+
- `1u32`.
195+
- `0i64`.
196+
- `1000`.
197+
- `10000`.
198+
- `1000000`.
157199

200+
## Guidance (Non-Normative)
158201

159-
## Error Wrapping
202+
Guidance is non-normative. Follow it unless it conflicts with MUST rules, rustfmt output, or explicit requirements.
160203

161-
- Add contextual messages at crate or module boundaries, and keep the original error as the source.
162-
- Use `#[error(transparent)]` only for thin wrappers where this crate adds no context and the upstream
163-
message is already sufficient for developers.
204+
### Declaration Order
205+
206+
- Inside `#[cfg(test)] mod tests`, prefer `use super::*;` before any other `use` statements.
207+
208+
### Imports and Headers
209+
210+
- If `crate::prelude::*` is imported, avoid redundant imports.
211+
212+
### Logging Rules
213+
214+
- Use a short, action-oriented message alongside structured fields.
215+
- Avoid creating temporary variables solely for logging.
216+
217+
### Error Wrapping
218+
219+
- Add contextual messages at crate or module boundaries and keep the original error as the source.
220+
- Use `#[error(transparent)]` only for thin wrappers where this crate adds no context and the upstream message is already sufficient for developers.
164221
- Prefer short, action-oriented messages that name the operation and include the source error.
165222

166-
Example:
223+
Example (non-normative):
167224

168225
```rust
169226
#[derive(Debug, thiserror::Error)]
170227
pub enum Error {
171228
#[error(transparent)]
172229
Utf8(#[from] std::str::Utf8Error),
173-
230+
174231
#[error("Failed to serialize JetStream payload: {0}.")]
175232
Json(#[from] serde_json::Error),
176233
}
177234
```
178235

179-
## Borrowing and Ownership
236+
### Borrowing and Ownership
180237

181238
- Prefer `&value` over `.as_ref()` or `.as_str()` where applicable.
182-
- Avoid `.clone()` unless it is required by ownership or lifetimes.
183-
- Use `into_iter()` when consuming collections intentionally.
184-
- Do not use scope blocks solely to end a borrow.
185-
- When an early release is required, use an explicit drop.
186-
- When the value is a reference, prefer `let _ = value;` to end the borrow without triggering a
187-
drop warning.
188-
- Avoid single-use `let` bindings that only forward a value; inline the expression unless it
189-
improves readability, error handling, or avoids repeated work.
190-
191-
## Numeric Literals
192-
193-
- When using a numeric type suffix, always separate the value and suffix with a single underscore:
194-
- Allowed: `10_f64`, `1_u32`, `0_i64`
195-
- Forbidden: `10f64`, `1u32`, `0i64`
196-
197-
- For decimal integer literals with more than three digits (ignoring the sign), insert an
198-
underscore every three digits from the right:
199-
- Allowed: `1_000`, `10_000`, `1_000_000`
200-
- Forbidden: `1000`, `10000`, `1000000`
239+
- Avoid `.clone()` unless it is required by ownership or lifetimes.
240+
- Use `into_iter()` when consuming collections intentionally.
241+
- Do not use scope blocks solely to end a borrow.
242+
- When an early release is required, use an explicit `drop`.
243+
- When the value is a reference, prefer `let _ = value;` to end the borrow without triggering a drop warning.
244+
- Avoid single-use `let` bindings that only forward a value; inline the expression unless it improves readability, error handling, or avoids repeated work.
201245

202-
## Vertical Spacing
246+
### Vertical Spacing
203247

204248
Inside Rust functions:
205249

206-
- Same-category statements: no blank lines.
207-
- Different categories: one blank line.
208-
- Before the final return or tail expression: exactly one blank line (unless single-expression
209-
body).
250+
- Do not insert blank lines within the same statement type.
251+
- Insert one blank line between different statement types.
252+
- Insert exactly one blank line before the final return or tail expression, unless the body is a single expression.
253+
254+
Treat statements as the same type when they share the same syntactic form or call target, such as:
255+
256+
- Multiple `let` statements.
257+
- Multiple `if` or `if let` statements.
258+
- Multiple `match` statements.
259+
- Multiple loop statements (`for`, `while`, `loop`).
260+
- Multiple macro calls (`println!`, `tracing::...`).
261+
- Multiple `Type::function(...)` calls.
262+
- Multiple `self.method(...)` calls.
263+
- Multiple assignment statements like `a = b`.
264+
These examples are not exhaustive. Apply the same rule to any repeated statement shape.

0 commit comments

Comments
 (0)