style guide: rewrite for Rust, guard against cargo fmt
code_style_guide.md was the generic C++ formulation of the Modified Allman style: it mandated camelCase for functions (every function in this crate is Rust snake_case, and rustc warns otherwise), three of its five examples taught try/catch brace placement for a construct Rust does not have, all examples were C++, and it instructed saving a .clang-format that does not exist and would not format Rust anyway. Its final YAML block was also missing the closing fence, so renderers swallowed the tail of the document. Since README defers to CONTRIBUTING and CONTRIBUTING defers here for the full rules, the contributor path terminated in the one document that contradicted the code.
Rewrite it for Rust: same principles (tabs, opening brace on its own line, compact "} else {", spaces inside non-empty parentheses), plus the rules the code follows but no document stated — snake_case for functions and variables, spaces inside non-empty attribute brackets, no spaces inside generics, aligned columns, comments in English. Examples are now idiomatic Rust: if/else, match, Result with the ? operator in place of try/catch, if let, struct + impl with attributes. The file declares itself the canonical reference, with CONTRIBUTING's bullets as the summary.
Replace the .clang-format section with the verified rustfmt situation: rustfmt cannot express this style (no option exists for spaces inside parentheses or attribute brackets, the brace-style options are nightly-only, and even on nightly Allman opening braces cannot combine with a compact "} else {"). Ship a rustfmt.toml with disable_all_formatting = true — a stable option, verified a no-op on rustfmt 1.8.0 — so an accidental cargo fmt or editor format-on-save can no longer rewrite the tree.
This commit is contained in:
@@ -1,169 +1,136 @@
|
|||||||
# Code Style Guide
|
# Code Style Guide
|
||||||
|
|
||||||
This project follows a **Modified Allman** brace and formatting style.
|
This project follows a **Modified Allman** brace and formatting style, applied to Rust. It prioritizes **visual clarity, symmetry, and logical separation of blocks** over strict line compactness.
|
||||||
It prioritizes **visual clarity, symmetry, and logical separation of blocks** over strict line compactness.
|
|
||||||
|
This file is the canonical style reference; the style bullets in [CONTRIBUTING.md](CONTRIBUTING.md) are a summary of it.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Overview
|
## Key principles
|
||||||
|
|
||||||
### Key Principles
|
|
||||||
- Indentation with **tabs** (width = 4).
|
- Indentation with **tabs** (width = 4).
|
||||||
- **Opening braces `{`** always start on a new line.
|
- **Opening braces `{`** start on their own line — for `fn`, `impl`, `struct`, `enum`, `trait`, `mod`, `if`, `for`, `while`, `loop` and `match`.
|
||||||
- **`} else {`** and **`} catch {`** appear on the same line for compact flow.
|
- **`} else {`** and **`} else if … {`** stay on the same line for compact flow.
|
||||||
- **Spaces inside parentheses only when non-empty:**
|
- **Spaces inside parentheses only when non-empty:**
|
||||||
- `( arg1, arg2 )`
|
- `( arg1, arg2 )`
|
||||||
- `main()`
|
- `main()`
|
||||||
- **Classes and structs:** PascalCase
|
- **Spaces inside attribute brackets only when non-empty:** `#[ derive( Clone, Debug ) ]`, `#[ cfg( test ) ]`.
|
||||||
- **Variables, objects, and functions:** camelCase
|
- **No spaces inside generics:** `Vec<String>`, `Option<i32>`, `Element<Msg>`.
|
||||||
- **Constants/macros:** UPPER_CASE_WITH_UNDERSCORES
|
- **Types, traits, and enum variants:** PascalCase.
|
||||||
|
- **Functions, methods, variables, and modules:** snake_case (the Rust convention; `rustc` warns on anything else).
|
||||||
|
- **Constants and statics:** UPPER_CASE_WITH_UNDERSCORES.
|
||||||
|
- **Aligned columns** in consecutive struct fields, match arms, or `let` groups where it aids scanning.
|
||||||
|
- **Comments in English**, only where the code cannot say it itself.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### `if / else` structure
|
### `if / else` structure
|
||||||
```cpp
|
|
||||||
if ( condition )
|
```rust
|
||||||
|
if condition
|
||||||
{
|
{
|
||||||
doSomething();
|
do_something();
|
||||||
|
} else if other_condition {
|
||||||
|
do_other_thing();
|
||||||
} else {
|
} else {
|
||||||
doSomethingElse( arg1, arg2 );
|
do_something_else( arg1, arg2 );
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### `try / catch` structure
|
### `match` structure
|
||||||
```cpp
|
|
||||||
try
|
```rust
|
||||||
|
match points.len()
|
||||||
{
|
{
|
||||||
runOperation();
|
0 => None,
|
||||||
} catch ( const std::exception& ex ) {
|
1 => Some( points[0].value ),
|
||||||
handleError( ex );
|
n => Some( total / n as f32 ),
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Class and method naming
|
### Error handling
|
||||||
```cpp
|
|
||||||
class DataAnalyzer
|
Rust has no `try / catch`; recoverable errors travel as `Result` and propagate with `?`. The block style applies to the `match` when a result is handled in place:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn load_config( path: &Path ) -> Result<Config, ConfigError>
|
||||||
{
|
{
|
||||||
public:
|
let text = std::fs::read_to_string( path )?;
|
||||||
DataAnalyzer( const std::string& filePath )
|
match toml::from_str( &text )
|
||||||
: filePath( filePath )
|
|
||||||
{
|
{
|
||||||
|
Ok( cfg ) => Ok( cfg ),
|
||||||
|
Err( e ) => Err( ConfigError::Parse( e ) ),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
void processDataAndGenerateReport()
|
`if let` follows the same brace rules as `if`:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
if let Some( ( rgba, w, h ) ) = icon( "general/right" )
|
||||||
|
{
|
||||||
|
it = it.trailing_icon( rgba, w, h );
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Structs, impls, and attributes
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[ derive( Clone, Debug ) ]
|
||||||
|
pub struct DataPoint
|
||||||
|
{
|
||||||
|
value: f32,
|
||||||
|
label: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataPoint
|
||||||
|
{
|
||||||
|
pub fn new( value: f32, label: impl Into<String> ) -> Self
|
||||||
{
|
{
|
||||||
try
|
Self
|
||||||
{
|
{
|
||||||
loadDataFromFile( filePath );
|
value,
|
||||||
analyzeResultsAndPrintSummary();
|
label: label.into(),
|
||||||
} catch ( const std::runtime_error& error ) {
|
|
||||||
std::cerr << "Error: " << error.what() << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
pub fn scaled( &self, factor: f32 ) -> f32
|
||||||
std::string filePath;
|
|
||||||
|
|
||||||
void loadDataFromFile( const std::string& path )
|
|
||||||
{
|
{
|
||||||
if ( path.empty() )
|
if factor <= 0.0
|
||||||
{
|
{
|
||||||
throw std::runtime_error( "File path cannot be empty." );
|
self.value
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Loading data from: " << path << std::endl;
|
self.value * factor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void analyzeResultsAndPrintSummary()
|
|
||||||
{
|
|
||||||
std::cout << "Analyzing data..." << std::endl;
|
|
||||||
std::cout << "Summary: OK" << std::endl;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### `main()` function
|
### `main()` function
|
||||||
```cpp
|
|
||||||
int main()
|
```rust
|
||||||
|
fn main()
|
||||||
{
|
{
|
||||||
DataAnalyzer analyzer( "results.csv" );
|
let analyzer = DataAnalyzer::new( "results.csv" );
|
||||||
|
|
||||||
try
|
if let Err( e ) = analyzer.process_and_report()
|
||||||
{
|
{
|
||||||
analyzer.processDataAndGenerateReport();
|
eprintln!( "Error: {e}" );
|
||||||
} catch ( const std::exception& ex ) {
|
std::process::exit( 1 );
|
||||||
std::cerr << "Unhandled exception: " << ex.what() << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## `.clang-format` configuration
|
## Tooling: do not run `cargo fmt`
|
||||||
|
|
||||||
Save this file as `.clang-format` in your project root:
|
`rustfmt` cannot express this style, so **never run `cargo fmt` on this codebase** — it would rewrite every file into the default style. Specifically:
|
||||||
|
|
||||||
```yaml
|
- There is **no rustfmt option for spaces inside parentheses or attribute brackets** (the historical `spaces_within_parens` options were removed from rustfmt).
|
||||||
# === Style: Modified Allman (tabs, compact else/catch, and selective parentheses spacing) ===
|
- The item brace styles (`brace_style`, `control_brace_style`) are **unstable, nightly-only** options.
|
||||||
# Naming conventions:
|
- Even on nightly, the combination of Allman opening braces with a compact `} else {` is not representable: `control_brace_style = "AlwaysNextLine"` also pushes `else` onto its own line.
|
||||||
# · Classes and structs: PascalCase (e.g., MyClass, PlayerController)
|
|
||||||
# · Variables, objects, and functions: camelCase (e.g., myVariable, calculateScore)
|
|
||||||
# · Constants or macros: UPPER_CASE_WITH_UNDERSCORES
|
|
||||||
# · if/else and try/catch share the same brace layout:
|
|
||||||
# if ( condition )
|
|
||||||
# {
|
|
||||||
# ...
|
|
||||||
# } else {
|
|
||||||
# ...
|
|
||||||
# }
|
|
||||||
# try
|
|
||||||
# {
|
|
||||||
# ...
|
|
||||||
# } catch ( const std::exception& e ) {
|
|
||||||
# ...
|
|
||||||
# }
|
|
||||||
|
|
||||||
BasedOnStyle: LLVM
|
The repository ships a `rustfmt.toml` containing only `disable_all_formatting = true`, so an accidental `cargo fmt` — or an editor with format-on-save wired to rustfmt — is a no-op instead of a 40 000-line diff. Style is enforced by review, not by a formatter.
|
||||||
|
|
||||||
IndentWidth: 4
|
|
||||||
UseTab: Always
|
|
||||||
|
|
||||||
BraceWrapping:
|
|
||||||
AfterClass: true
|
|
||||||
AfterControlStatement: true
|
|
||||||
AfterEnum: true
|
|
||||||
AfterFunction: true
|
|
||||||
AfterNamespace: true
|
|
||||||
AfterStruct: true
|
|
||||||
AfterUnion: true
|
|
||||||
BeforeCatch: false
|
|
||||||
BeforeElse: false
|
|
||||||
IndentBraces: false
|
|
||||||
SplitEmptyFunction: false
|
|
||||||
SplitEmptyRecord: false
|
|
||||||
SplitEmptyNamespace: false
|
|
||||||
|
|
||||||
AllowShortIfStatementsOnASingleLine: false
|
|
||||||
AllowShortLoopsOnASingleLine: false
|
|
||||||
AllowShortFunctionsOnASingleLine: false
|
|
||||||
|
|
||||||
SpaceBeforeParens: Always
|
|
||||||
SpaceInEmptyParentheses: false
|
|
||||||
SpaceInParens: true
|
|
||||||
SpacesInAngles: false
|
|
||||||
SpacesInCStyleCastParentheses: true
|
|
||||||
SpacesInSquareBrackets: false
|
|
||||||
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
|
||||||
ColumnLimit: 0
|
|
||||||
AlignConsecutiveAssignments: true
|
|
||||||
AlignConsecutiveDeclarations: true
|
|
||||||
AlignEscapedNewlines: Left
|
|
||||||
AlignOperands: true
|
|
||||||
AlignTrailingComments: true
|
|
||||||
|
|
||||||
BreakBeforeBraces: Allman
|
|
||||||
|
|||||||
4
rustfmt.toml
Normal file
4
rustfmt.toml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# This codebase uses the Modified Allman style described in code_style_guide.md,
|
||||||
|
# which rustfmt cannot express. Formatting is disabled so an accidental
|
||||||
|
# `cargo fmt` (or editor format-on-save) is a no-op.
|
||||||
|
disable_all_formatting = true
|
||||||
Reference in New Issue
Block a user