diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:11:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:13:23 +0000 |
commit | 20431706a863f92cb37dc512fef6e48d192aaf2c (patch) | |
tree | 2867f13f5fd5437ba628c67d7f87309ccadcd286 /src/doc/style-guide | |
parent | Releasing progress-linux version 1.65.0+dfsg1-2~progress7.99u1. (diff) | |
download | rustc-20431706a863f92cb37dc512fef6e48d192aaf2c.tar.xz rustc-20431706a863f92cb37dc512fef6e48d192aaf2c.zip |
Merging upstream version 1.66.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/doc/style-guide')
-rw-r--r-- | src/doc/style-guide/book.toml | 8 | ||||
-rw-r--r-- | src/doc/style-guide/src/README.md | 190 | ||||
-rw-r--r-- | src/doc/style-guide/src/SUMMARY.md | 11 | ||||
-rw-r--r-- | src/doc/style-guide/src/advice.md | 34 | ||||
-rw-r--r-- | src/doc/style-guide/src/cargo.md | 78 | ||||
-rw-r--r-- | src/doc/style-guide/src/expressions.md | 850 | ||||
-rw-r--r-- | src/doc/style-guide/src/items.md | 565 | ||||
-rw-r--r-- | src/doc/style-guide/src/principles.md | 51 | ||||
-rw-r--r-- | src/doc/style-guide/src/statements.md | 150 | ||||
-rw-r--r-- | src/doc/style-guide/src/types.md | 58 |
10 files changed, 1995 insertions, 0 deletions
diff --git a/src/doc/style-guide/book.toml b/src/doc/style-guide/book.toml new file mode 100644 index 000000000..056aec8cd --- /dev/null +++ b/src/doc/style-guide/book.toml @@ -0,0 +1,8 @@ +[book] +title = "The Rust Style Guide" +author = "The Rust Style Team" +multilingual = false +src = "src" + +[output.html] +git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide/" diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md new file mode 100644 index 000000000..adb73a7ee --- /dev/null +++ b/src/doc/style-guide/src/README.md @@ -0,0 +1,190 @@ +# Rust Style Guide + +## Motivation - why use a formatting tool? + +Formatting code is a mostly mechanical task which takes both time and mental +effort. By using an automatic formatting tool, a programmer is relieved of +this task and can concentrate on more important things. + +Furthermore, by sticking to an established style guide (such as this one), +programmers don't need to formulate ad hoc style rules, nor do they need to +debate with other programmers what style rules should be used, saving time, +communication overhead, and mental energy. + +Humans comprehend information through pattern matching. By ensuring that all +Rust code has similar formatting, less mental effort is required to comprehend a +new project, lowering the barrier to entry for new developers. + +Thus, there are productivity benefits to using a formatting tool (such as +rustfmt), and even larger benefits by using a community-consistent formatting, +typically by using a formatting tool's default settings. + + +## Formatting conventions + +### Indentation and line width + +* Use spaces, not tabs. +* Each level of indentation must be four spaces (that is, all indentation + outside of string literals and comments must be a multiple of four). +* The maximum width for a line is 100 characters. +* A tool should be configurable for all three of these variables. + + +### Blank lines + +Separate items and statements by either zero or one blank lines (i.e., one or +two newlines). E.g, + +```rust +fn foo() { + let x = ...; + + let y = ...; + let z = ...; +} + +fn bar() {} +fn baz() {} +``` + +Formatting tools should make the bounds on blank lines configurable: there +should be separate minimum and maximum numbers of newlines between both +statements and (top-level) items (i.e., four options). As described above, the +defaults for both statements and items should be minimum: 1, maximum: 2. + + +### [Module-level items](items.md) +### [Statements](statements.md) +### [Expressions](expressions.md) +### [Types](types.md) + + +### Comments + +The following guidelines for comments are recommendations only, a mechanical +formatter might skip formatting of comments. + +Prefer line comments (`//`) to block comments (`/* ... */`). + +When using line comments there should be a single space after the opening sigil. + +When using single-line block comments there should be a single space after the +opening sigil and before the closing sigil. Multi-line block comments should +have a newline after the opening sigil and before the closing sigil. + +Prefer to put a comment on its own line. Where a comment follows code, there +should be a single space before it. Where a block comment is inline, there +should be surrounding whitespace as if it were an identifier or keyword. There +should be no trailing whitespace after a comment or at the end of any line in a +multi-line comment. Examples: + +```rust +// A comment on an item. +struct Foo { ... } + +fn foo() {} // A comment after an item. + +pub fn foo(/* a comment before an argument */ x: T) {...} +``` + +Comments should usually be complete sentences. Start with a capital letter, end +with a period (`.`). An inline block comment may be treated as a note without +punctuation. + +Source lines which are entirely a comment should be limited to 80 characters +in length (including comment sigils, but excluding indentation) or the maximum +width of the line (including comment sigils and indentation), whichever is +smaller: + +```rust +// This comment goes up to the ................................. 80 char margin. + +{ + // This comment is .............................................. 80 chars wide. +} + +{ + { + { + { + { + { + // This comment is limited by the ......................... 100 char margin. + } + } + } + } + } +} +``` + +#### Doc comments + +Prefer line comments (`///`) to block comments (`/** ... */`). + +Prefer outer doc comments (`///` or `/** ... */`), only use inner doc comments +(`//!` and `/*! ... */`) to write module-level or crate-level documentation. + +Doc comments should come before attributes. + +### Attributes + +Put each attribute on its own line, indented to the level of the item. +In the case of inner attributes (`#!`), indent it to the level of the inside of +the item. Prefer outer attributes, where possible. + +For attributes with argument lists, format like functions. + +```rust +#[repr(C)] +#[foo(foo, bar)] +struct CRepr { + #![repr(C)] + x: f32, + y: f32, +} +``` + +For attributes with an equal sign, there should be a single space before and +after the `=`, e.g., `#[foo = 42]`. + +There must only be a single `derive` attribute. Note for tool authors: if +combining multiple `derive` attributes into a single attribute, the ordering of +the derived names should be preserved. E.g., `#[derive(bar)] #[derive(foo)] +struct Baz;` should be formatted to `#[derive(bar, foo)] struct Baz;`. + +### *small* items + +In many places in this guide we specify that a formatter may format an item +differently if it is *small*, for example struct literals: + +```rust +// Normal formatting +Foo { + f1: an_expression, + f2: another_expression(), +} + +// *small* formatting +Foo { f1, f2 } +``` + +We leave it to individual tools to decide on exactly what *small* means. In +particular, tools are free to use different definitions in different +circumstances. + +Some suitable heuristics are the size of the item (in characters) or the +complexity of an item (for example, that all components must be simple names, +not more complex sub-expressions). For more discussion on suitable heuristics, +see [this issue](https://github.com/rust-lang-nursery/fmt-rfcs/issues/47). + +Tools should give the user an option to ignore such heuristics and always use +the normal formatting. + + +## [Non-formatting conventions](advice.md) + +## [Cargo.toml conventions](cargo.md) + +## [Principles used for deciding these guidelines](principles.md) diff --git a/src/doc/style-guide/src/SUMMARY.md b/src/doc/style-guide/src/SUMMARY.md new file mode 100644 index 000000000..004692fa6 --- /dev/null +++ b/src/doc/style-guide/src/SUMMARY.md @@ -0,0 +1,11 @@ +# Summary + +[Introduction](README.md) + +- [Module-level items](items.md) +- [Statements](statements.md) +- [Expressions](expressions.md) +- [Types](types.md) +- [Non-formatting conventions](advice.md) +- [`Cargo.toml` conventions](cargo.md) +- [Principles used for deciding these guidelines](principles.md) diff --git a/src/doc/style-guide/src/advice.md b/src/doc/style-guide/src/advice.md new file mode 100644 index 000000000..ab4b92b0a --- /dev/null +++ b/src/doc/style-guide/src/advice.md @@ -0,0 +1,34 @@ +# Other style advice + +## Expressions + +Prefer to use Rust's expression oriented nature where possible; + +```rust +// use +let x = if y { 1 } else { 0 }; +// not +let x; +if y { + x = 1; +} else { + x = 0; +} +``` + +## Names + + * Types shall be `UpperCamelCase`, + * Enum variants shall be `UpperCamelCase`, + * Struct fields shall be `snake_case`, + * Function and method names shall be `snake_case`, + * Local variables shall be `snake_case`, + * Macro names shall be `snake_case`, + * Constants (`const`s and immutable `static`s) shall be `SCREAMING_SNAKE_CASE`. + * When a name is forbidden because it is a reserved word (e.g., `crate`), use a + trailing underscore to make the name legal (e.g., `crate_`), or use raw + identifiers if possible. + +### Modules + +Avoid `#[path]` annotations where possible. diff --git a/src/doc/style-guide/src/cargo.md b/src/doc/style-guide/src/cargo.md new file mode 100644 index 000000000..f4993ba06 --- /dev/null +++ b/src/doc/style-guide/src/cargo.md @@ -0,0 +1,78 @@ +# Cargo.toml conventions + +## Formatting conventions + +Use the same line width and indentation as Rust code. + +Put a blank line between the last key-value pair in a section and the header of +the next section. Do not place a blank line between section headers and the +key-value pairs in that section, or between key-value pairs in a section. + +Sort key names alphabetically within each section, with the exception of the +`[package]` section. Put the `[package]` section at the top of the file; put +the `name` and `version` keys in that order at the top of that section, +followed by the remaining keys other than `description` in alphabetical order, +followed by the `description` at the end of that section. + +Don't use quotes around any standard key names; use bare keys. Only use quoted +keys for non-standard keys whose names require them, and avoid introducing such +key names when possible. See the [TOML +specification](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md#table) +for details. + +Put a single space both before and after the `=` between a key and value. Do +not indent any key names; start all key names at the start of a line. + +Use multi-line strings (rather than newline escape sequences) for any string +values that include multiple lines, such as the crate description. + +For array values, such as a list of authors, put the entire list on the same +line as the key, if it fits. Otherwise, use block indentation: put a newline +after the opening square bracket, indent each item by one indentation level, +put a comma after each item (including the last), and put the closing square +bracket at the start of a line by itself after the last item. + +```rust +authors = [ + "A Uthor <a.uthor@example.org>", + "Another Author <author@example.net>", +] +``` + +For table values, such as a crate dependency with a path, write the entire +table using curly braces and commas on the same line as the key if it fits. If +the entire table does not fit on the same line as the key, separate it out into +a separate section with key-value pairs: + +```toml +[dependencies] +crate1 = { path = "crate1", version = "1.2.3" } + +[dependencies.extremely_long_crate_name_goes_here] +path = "extremely_long_path_name_goes_right_here" +version = "4.5.6" +``` + +## Metadata conventions + +The authors list should consist of strings that each contain an author name +followed by an email address in angle brackets: `Full Name <email@address>`. +It should not contain bare email addresses, or names without email addresses. +(The authors list may also include a mailing list address without an associated +name.) + +The license field must contain a valid [SPDX +expression](https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60), +using valid [SPDX license names](https://spdx.org/licenses/). (As an exception, +by widespread convention, the license field may use `/` in place of ` OR `; for +example, `MIT/Apache-2.0`.) + +The homepage field, if present, must consist of a single URL, including the +scheme (e.g. `https://example.org/`, not just `example.org`.) + +Within the description field, wrap text at 80 columns. Don't start the +description field with the name of the crate (e.g. "cratename is a ..."); just +describe the crate itself. If providing a multi-sentence description, the first +sentence should go on a line by itself and summarize the crate, like the +subject of an email or commit message; subsequent sentences can then describe +the crate in more detail. diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md new file mode 100644 index 000000000..c7d0446dd --- /dev/null +++ b/src/doc/style-guide/src/expressions.md @@ -0,0 +1,850 @@ +## Expressions + +### Blocks + +A block expression should have a newline after the initial `{` and before the +terminal `}`. Any qualifier before the block (e.g., `unsafe`) should always be +on the same line as the opening brace, and separated with a single space. The +contents of the block should be block indented: + +```rust +fn block_as_stmt() { + a_call(); + + { + a_call_inside_a_block(); + + // a comment in a block + the_value + } +} + +fn block_as_expr() { + let foo = { + a_call_inside_a_block(); + + // a comment in a block + the_value + }; +} + +fn unsafe_block_as_stmt() { + a_call(); + + unsafe { + a_call_inside_a_block(); + + // a comment in a block + the_value + } +} +``` + +If a block has an attribute, it should be on its own line: + +```rust +fn block_as_stmt() { + #[an_attribute] + { + #![an_inner_attribute] + + // a comment in a block + the_value + } +} +``` + +Avoid writing comments on the same line as the braces. + +An empty block should be written as `{}`. + +A block may be written on a single line if: + +* it is either used in expression position (not statement position) or is an + unsafe block in statement position +* contains a single-line expression and no statements +* contains no comments + +A single line block should have spaces after the opening brace and before the +closing brace. + +Examples: + +```rust +fn main() { + // Single line + let _ = { a_call() }; + let _ = unsafe { a_call() }; + + // Not allowed on one line + // Statement position. + { + a_call() + } + + // Contains a statement + let _ = { + a_call(); + }; + unsafe { + a_call(); + } + + // Contains a comment + let _ = { + // A comment + }; + let _ = { + // A comment + a_call() + }; + + // Multiple lines + let _ = { + a_call(); + another_call() + }; + let _ = { + a_call( + an_argument, + another_arg, + ) + }; +} +``` + + +### Closures + +Don't put any extra spaces before the first `|` (unless the closure is prefixed +by `move`); put a space between the second `|` and the expression of the +closure. Between the `|`s, you should use function definition syntax, however, +elide types where possible. + +Use closures without the enclosing `{}`, if possible. Add the `{}` when you have +a return type, when there are statements, there are comments in the body, or the +body expression spans multiple lines and is a control-flow expression. If using +braces, follow the rules above for blocks. Examples: + +```rust +|arg1, arg2| expr + +move |arg1: i32, arg2: i32| -> i32 { + expr1; + expr2 +} + +|| Foo { + field1, + field2: 0, +} + +|| { + if true { + blah + } else { + boo + } +} + +|x| unsafe { + expr +} +``` + + +### Struct literals + +If a struct literal is *small* it may be formatted on a single line. If not, +each field should be on it's own, block-indented line. There should be a +trailing comma in the multi-line form only. There should be a space after the +colon only. + +There should be a space before the opening brace. In the single-line form there +should be spaces after the opening brace and before the closing brace. + +```rust +Foo { field1, field2: 0 } +let f = Foo { + field1, + field2: an_expr, +}; +``` + +Functional record update syntax is treated like a field, but it must never have +a trailing comma. There should be no space after `..`. + +let f = Foo { + field1, + ..an_expr +}; + + +### Tuple literals + +Use a single-line form where possible. There should not be spaces around the +parentheses. Where a single-line form is not possible, each element of the tuple +should be on its own block-indented line and there should be a trailing comma. + +```rust +(a, b, c) + +let x = ( + a_long_expr, + another_very_long_expr, +); +``` + + +### Tuple struct literals + +There should be no space between the identifier and the opening parenthesis. +Otherwise, follow the rules for tuple literals, e.g., `Foo(a, b)`. + + +### Enum literals + +Follow the formatting rules for the various struct literals. Prefer using the +name of the enum as a qualifying name, unless the enum is in the prelude. E.g., + +```rust +Foo::Bar(a, b) +Foo::Baz { + field1, + field2: 1001, +} +Ok(an_expr) +``` + + +### Array literals + +For simple array literals, avoid line breaking, no spaces around square +brackets, contents of the array should be separated by commas and spaces. If +using the repeating initialiser, there should be a space after the semicolon +only. Apply the same rules if using the `vec!` or similar macros (always use +square brackets here). Examples: + +```rust +fn main() { + [1, 2, 3]; + vec![a, b, c, d]; + let a = [42; 10]; +} +``` + +If a line must be broken, prefer breaking only after the `;`, if possible. +Otherwise, follow the rules below for function calls. In any case, the contents +of the initialiser should be block indented and there should be line breaks +after the opening bracket and before the closing bracket: + +```rust +fn main() { + [ + a_long_expression(); + 1234567890 + ] + let x = [ + an_expression, + another_expression, + a_third_expression, + ]; +} +``` + + +### Array accesses, indexing, and slicing. + +No spaces around the square brackets, avoid breaking lines if possible, never +break a line between the target expression and the opening bracket. If the +indexing expression covers multiple lines, then it should be block indented and +there should be newlines after the opening brackets and before the closing +bracket. However, this should be avoided where possible. + +Examples: + +```rust +fn main() { + foo[42]; + &foo[..10]; + bar[0..100]; + foo[4 + 5 / bar]; + a_long_target[ + a_long_indexing_expression + ]; +} +``` + +### Unary operations + +Do not include a space between a unary op and its operand (i.e., `!x`, not +`! x`). However, there must be a space after `&mut`. Avoid line-breaking +between a unary operator and its operand. + +### Binary operations + +Do include spaces around binary ops (i.e., `x + 1`, not `x+1`) (including `=` +and other assignment operators such as `+=` or `*=`). + +For comparison operators, because for `T op U`, `&T op &U` is also implemented: +if you have `t: &T`, and `u: U`, prefer `*t op u` to `t op &u`. In general, +within expressions, prefer dereferencing to taking references. + +Use parentheses liberally, do not necessarily elide them due to precedence. +Tools should not automatically insert or remove parentheses. Do not use spaces +to indicate precedence. + +If line-breaking, put the operator on a new line and block indent. Put each +sub-expression on its own line. E.g., + +```rust +foo_bar + + bar + + baz + + qux + + whatever +``` + +Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather +than at other binary operators. + +### Control flow + +Do not include extraneous parentheses for `if` and `while` expressions. + +```rust +if true { +} +``` + +is better than + +```rust +if (true) { +} +``` + +Do include extraneous parentheses if it makes an arithmetic or logic expression +easier to understand (`(x * 15) + (y * 20)` is fine) + +### Function calls + +Do not put a space between the function name, and the opening parenthesis. + +Do not put a space between an argument, and the comma which follows. + +Do put a space between an argument, and the comma which precedes it. + +Prefer not to break a line in the callee expression. + +#### Single-line calls + +Do not put a space between the function name and open paren, between the open +paren and the first argument, or between the last argument and the close paren. + +Do not put a comma after the last argument. + +```rust +foo(x, y, z) +``` + +#### Multi-line calls + +If the function call is not *small*, it would otherwise over-run the max width, +or any argument or the callee is multi-line, then the call should be formatted +across multiple lines. In this case, each argument should be on it's own block- +indented line, there should be a newline after the opening parenthesis and +before the closing parenthesis, and there should be a trailing comma. E.g., + +```rust +a_function_call( + arg1, + a_nested_call(a, b), +) +``` + + +### Method calls + +Follow the function rules for calling. + +Do not put any spaces around the `.`. + +```rust +x.foo().bar().baz(x, y, z); +``` + + +### Macro uses + +Macros which can be parsed like other constructs should be formatted like those +constructs. For example, a macro use `foo!(a, b, c)` can be parsed like a +function call (ignoring the `!`), therefore it should be formatted following the +rules for function calls. + +#### Special case macros + +Macros which take a format string and where all other arguments are *small* may +be formatted with arguments before and after the format string on a single line +and the format string on its own line, rather than putting each argument on its +own line. For example, + +```rust +println!( + "Hello {} and {}", + name1, name2, +); + +assert_eq!( + x, y, + "x and y were not equal, see {}", + reason, +); +``` + + +### Casts (`as`) + +Put spaces before and after `as`: + +```rust +let cstr = "Hi\0" as *const str as *const [u8] as *const std::os::raw::c_char; +``` + + +### Chains of fields and method calls + +A chain is a sequence of field accesses and/or method calls. A chain may also +include the try operator ('?'). E.g., `a.b.c().d` or `foo?.bar().baz?`. + +Prefer formatting on one line if possible, and the chain is *small*. If +formatting on multiple lines, each field access or method call in the chain +should be on its own line with the line-break before the `.` and after any `?`. +Each line should be block-indented. E.g., + +```rust +let foo = bar + .baz? + .qux(); +``` + +If the length of the last line of the first element plus its indentation is +less than or equal to the indentation of the second line (and there is space), +then combine the first and second lines, e.g., + +```rust +x.baz? + .qux() + +let foo = x + .baz? + .qux(); + +foo( + expr1, + expr2, +).baz? + .qux(); +``` + +#### Multi-line elements + +If any element in a chain is formatted across multiple lines, then that element +and any later elements must be on their own line. Earlier elements may be kept +on a single line. E.g., + +```rust +a.b.c()?.d + .foo( + an_expr, + another_expr, + ) + .bar + .baz +``` + +Note there is block indent due to the chain and the function call in the above +example. + +Prefer formatting the whole chain in multi-line style and each element on one +line, rather than putting some elements on multiple lines and some on a single +line, e.g., + +```rust +// Better +self.pre_comment + .as_ref() + .map_or(false, |comment| comment.starts_with("//")) + +// Worse +self.pre_comment.as_ref().map_or( + false, + |comment| comment.starts_with("//"), +) +``` + +### Control flow expressions + +This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for` +expressions. + +The keyword, any initial clauses, and the opening brace of the block should be +on a single line. The usual rules for [block formatting](#blocks) should be +applied to the block. + +If there is an `else` component, then the closing brace, `else`, any following +clause, and the opening brace should all be on the same line. There should be a +single space before and after the `else` keyword. For example: + +```rust +if ... { + ... +} else { + ... +} + +if let ... { + ... +} else if ... { + ... +} else { + ... +} +``` + +If the control line needs to be broken, then prefer to break before the `=` in +`* let` expressions and before `in` in a `for` expression; the following line +should be block indented. If the control line is broken for any reason, then the +opening brace should be on its own line and not indented. Examples: + +```rust +while let Some(foo) + = a_long_expression +{ + ... +} + +for foo + in a_long_expression +{ + ... +} + +if a_long_expression + && another_long_expression + || a_third_long_expression +{ + ... +} +``` + +Where the initial clause is multi-lined and ends with one or more closing +parentheses, square brackets, or braces, and there is nothing else on that line, +and that line is not indented beyond the indent on the first line of the control +flow expression, then the opening brace of the block should be put on the same +line with a preceding space. For example: + +```rust +if !self.config.file_lines().intersects( + &self.codemap.lookup_line_range( + stmt.span, + ), +) { // Opening brace on same line as initial clause. + ... +} +``` + + +#### Single line `if else` + +Formatters may place an `if else` or `if let else` on a single line if it occurs +in expression context (i.e., is not a standalone statement), it contains a +single `else` clause, and is *small*. For example: + +```rust +let y = if x { 0 } else { 1 }; + +// Examples that must be multi-line. +let y = if something_very_long { + not_small +} else { + also_not_small +}; + +if x { + 0 +} else { + 1 +} +``` + + +### Match + +Prefer not to line-break inside the discriminant expression. There must always +be a line break after the opening brace and before the closing brace. The match +arms must be block indented once: + +```rust +match foo { + // arms +} + +let x = match foo.bar.baz() { + // arms +}; +``` + +Use a trailing comma for a match arm if and only if not using a block. + +Never start a match arm pattern with `|`, e.g., + +```rust +match foo { + // Don't do this. + | foo => bar, + // Or this. + | a_very_long_pattern + | another_pattern + | yet_another_pattern + | a_forth_pattern => { + ... + } +} +``` + +Prefer + + +```rust +match foo { + foo => bar, + a_very_long_pattern + | another_pattern + | yet_another_pattern + | a_forth_pattern => { + ... + } +} +``` + +Avoid splitting the left-hand side (before the `=>`) of a match arm where +possible. If the right-hand side of the match arm is kept on the same line, +never use a block (unless the block is empty). + +If the right-hand side consists of multiple statements or has line comments or +the start of the line cannot be fit on the same line as the left-hand side, use +a block. + +The body of a block arm should be block indented once. + +Examples: + +```rust +match foo { + foo => bar, + a_very_long_patten | another_pattern if an_expression() => { + no_room_for_this_expression() + } + foo => { + // A comment. + an_expression() + } + foo => { + let a = statement(); + an_expression() + } + bar => {} + // Trailing comma on last item. + foo => bar, +} +``` + +If the body is a single expression with no line comments and not a control flow +expression, then it may be started on the same line as the right-hand side. If +not, then it must be in a block. Example, + +```rust +match foo { + // A combinable expression. + foo => a_function_call(another_call( + argument1, + argument2, + )), + // A non-combinable expression + bar => { + a_function_call( + another_call( + argument1, + argument2, + ), + another_argument, + ) + } +} +``` + +#### Line-breaking + +Where it is possible to use a block form on the right-hand side and avoid +breaking the left-hand side, do that. E.g. + +```rust + // Assuming the following line does done fit in the max width + a_very_long_pattern | another_pattern => ALongStructName { + ... + }, + // Prefer this + a_very_long_pattern | another_pattern => { + ALongStructName { + ... + } + } + // To splitting the pattern. +``` + +Never break after `=>` without using the block form of the body. + +If the left-hand side must be split and there is an `if` clause, break before +the `if` and block indent. In this case, always use a block body and start the +body on a new line: + +```rust + a_very_long_pattern | another_pattern + if expr => + { + ... + } +``` + +If required to break the pattern, put each clause of the pattern on its own +line with no additional indent, breaking before the `|`. If there is an `if` +clause, then you must use the above form: + +```rust + a_very_long_pattern + | another_pattern + | yet_another_pattern + | a_forth_pattern => { + ... + } + a_very_long_pattern + | another_pattern + | yet_another_pattern + | a_forth_pattern + if expr => + { + ... + } +``` + +If the pattern is multi-line, and the last line is less wide than the indent, do +not put the `if` clause on a newline. E.g., + +```rust + Token::Dimension { + value, + ref unit, + .. + } if num_context.is_ok(context.parsing_mode, value) => { + ... + } +``` + +If every clause in a pattern is *small*, but does not fit on one line, then the +pattern may be formatted across multiple lines with as many clauses per line as +possible. Again break before a `|`: + +```rust + foo | bar | baz + | qux => { + ... + } +``` + +We define a pattern clause to be *small* if it matches the following grammar: + +``` +[small, ntp]: + - single token + - `&[single-line, ntp]` + +[small]: + - `[small, ntp]` + - unary tuple constructor `([small, ntp])` + - `&[small]` +``` + +E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not. + + +### Combinable expressions + +Where a function call has a single argument, and that argument is formatted +across multiple-lines, the outer call may be formatted as if it were a single- +line call. The same combining behaviour may be applied to any similar +expressions which have multi-line, block-indented lists of sub-expressions +delimited by parentheses (e.g., macros or tuple struct literals). E.g., + +```rust +foo(bar( + an_expr, + another_expr, +)) + +let x = foo(Bar { + field: whatever, +}); + +foo(|param| { + action(); + foo(param) +}) +``` + +Such behaviour should extend recursively, however, tools may choose to limit the +depth of nesting. + +Only where the multi-line sub-expression is a closure with an explicit block, +this combining behaviour may be used where there are other arguments, as long as +all the arguments and the first line of the closure fit on the first line, the +closure is the last argument, and there is only one closure argument: + +```rust +foo(first_arg, x, |param| { + action(); + foo(param) +}) +``` + + +### Ranges + +Do not put spaces in ranges, e.g., `0..10`, `x..=y`, `..x.len()`, `foo..`. + +When writing a range with both upper and lower bounds, if the line must be +broken, break before the range operator and block indent the second line: + +```rust +a_long_expression + ..another_long_expression +``` + +For the sake of indicating precedence, we recommend that if either bound is a +compound expression, then use parentheses around it, e.g., `..(x + 1)`, +`(x.f)..(x.f.len())`, or `0..(x - 10)`. + + +### Hexadecimal literals + +Hexadecimal literals may use upper- or lower-case letters, but they must not be +mixed within the same literal. Projects should use the same case for all +literals, but we do not make a recommendation for either lower- or upper-case. +Tools should have an option to convert mixed case literals to upper-case, and +may have an option to convert all literals to either lower- or upper-case. + + +## Patterns + +Patterns should be formatted like their corresponding expressions. See the +section on `match` for additional formatting for patterns in match arms. diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md new file mode 100644 index 000000000..283597535 --- /dev/null +++ b/src/doc/style-guide/src/items.md @@ -0,0 +1,565 @@ +## Items + +`extern crate` statements must be first in a file. They must be ordered +alphabetically. + +`use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`) +must come before other items. We recommend that imports come before module +declarations; if imports and modules are separated, then they should be ordered +alphabetically. When sorting, `self` and `super` must come before any other +names. Module declarations should not be moved if they are annotated with +`#[macro_use]`, since that may be semantics changing. + +Tools should make the above ordering optional. + + +### Function definitions + +In Rust, one finds functions by searching for `fn [function-name]`; It's +important that you style your code so that it's very searchable in this way. + +The proper ordering and spacing is: + +```rust +[pub] [unsafe] [extern ["ABI"]] fn foo(arg1: i32, arg2: i32) -> i32 { + ... +} +``` + +Avoid comments within the signature itself. + +If the function signature does not fit on one line, then break after the opening +parenthesis and before the closing parenthesis and put each argument on its own +block-indented line. For example, + +```rust +fn foo( + arg1: i32, + arg2: i32, +) -> i32 { + ... +} +``` + +Note the trailing comma on the last argument. + + +### Tuples and tuple structs + +Write the type list as you would a parameter list to a function. + +Build a tuple or tuple struct as you would call a function. + +#### Single-line + +```rust +struct Bar(Type1, Type2); + +let x = Bar(11, 22); +let y = (11, 22, 33); +``` + +### Enums + +In the declaration, put each variant on its own line, block indented. + +Format each variant accordingly as either a struct, tuple struct, or identifier, +which doesn't require special formatting (but without the `struct` keyword. + +```rust +enum FooBar { + First(u32), + Second, + Error { + err: Box<Error>, + line: u32, + }, +} +``` + +If a struct variant is [*small*](index.html#small-items), it may be formatted on +one line. In this case, do not use a trailing comma for the field list, but do +put spaces around each brace: + +```rust +enum FooBar { + Error { err: Box<Error>, line: u32 }, +} +``` + +In an enum with multiple struct variants, if any struct variant is written on +multiple lines, then the multi-line formatting should be used for all struct +variants. However, such a situation might be an indication that you should +factor out the fields of the variant into their own struct. + + +### Structs and Unions + +Struct names follow on the same line as the `struct` keyword, with the opening +brace on the same line when it fits within the right margin. All struct fields +are indented once and end with a trailing comma. The closing brace is not +indented and appears on its own line. + +```rust +struct Foo { + a: A, + b: B, +} +``` + +If and only if the type of a field does not fit within the right margin, it is +pulled down to its own line and indented again. + +```rust +struct Foo { + a: A, + long_name: + LongType, +} +``` + +Prefer using a unit struct (e.g., `struct Foo;`) to an empty struct (e.g., +`struct Foo();` or `struct Foo {}`, these only exist to simplify code +generation), but if you must use an empty struct, keep it on one line with no +space between the braces: `struct Foo;` or `struct Foo {}`. + +The same guidelines are used for untagged union declarations. + +```rust +union Foo { + a: A, + b: B, + long_name: + LongType, +} +``` + + +### Tuple structs + +Put the whole struct on one line if possible. Types in the parentheses should be +separated by a comma and space with no trailing comma. No spaces around the +parentheses or semi-colon: + +```rust +pub struct Foo(String, u8); +``` + +Prefer unit structs to empty tuple structs (these only exist to simplify code +generation), e.g., `struct Foo;` rather than `struct Foo();`. + +For more than a few fields, prefer a proper struct with named fields. Given +this, a tuple struct should always fit on one line. If it does not, block format +the fields with a field on each line and a trailing comma: + +```rust +pub struct Foo( + String, + u8, +); +``` + + +### Traits + +Trait items should be block-indented. If there are no items, the trait may be +formatted on a single line. Otherwise there should be line-breaks after the +opening brace and before the closing brace: + +```rust +trait Foo {} + +pub trait Bar { + ... +} +``` + +If the trait has bounds, there should be a space after the colon but not before +and before and after each `+`, e.g., + +```rust +trait Foo: Debug + Bar {} +``` + +Prefer not to line-break in the bounds if possible (consider using a `where` +clause). Prefer to break between bounds than to break any individual bound. If +you must break the bounds, put each bound (including the first) on its own +block-indented line, break before the `+` and put the opening brace on its own +line: + +```rust +pub trait IndexRanges: + Index<Range<usize>, Output=Self> + + Index<RangeTo<usize>, Output=Self> + + Index<RangeFrom<usize>, Output=Self> + + Index<RangeFull, Output=Self> +{ + ... +} +``` + + +### Impls + +Impl items should be block indented. If there are no items, the impl may be +formatted on a single line. Otherwise there should be line-breaks after the +opening brace and before the closing brace: + +```rust +impl Foo {} + +impl Bar for Foo { + ... +} +``` + +Avoid line-breaking in the signature if possible. If a line break is required in +a non-inherent impl, break immediately before `for`, block indent the concrete type +and put the opening brace on its own line: + +```rust +impl Bar + for Foo +{ + ... +} +``` + + +### Extern crate + +`extern crate foo;` + +Use spaces around keywords, no spaces around the semi-colon. + + +### Modules + +```rust +mod foo { +} +``` + +```rust +mod foo; +``` + +Use spaces around keywords and before the opening brace, no spaces around the +semi-colon. + +### macro\_rules! + +Use `{}` for the full definition of the macro. + +```rust +macro_rules! foo { +} +``` + + +### Generics + +Prefer to put a generics clause on one line. Break other parts of an item +declaration rather than line-breaking a generics clause. If a generics clause is +large enough to require line-breaking, you should prefer to use a `where` clause +instead. + +Do not put spaces before or after `<` nor before `>`. Only put a space after `>` +if it is followed by a word or opening brace, not an opening parenthesis. There +should be a space after each comma and no trailing comma. + +```rust +fn foo<T: Display, U: Debug>(x: Vec<T>, y: Vec<U>) ... + +impl<T: Display, U: Debug> SomeType<T, U> { ... +``` + +If the generics clause must be formatted across multiple lines, each parameter +should have its own block-indented line, there should be newlines after the +opening bracket and before the closing bracket, and the should be a trailing +comma. + +```rust +fn foo< + T: Display, + U: Debug, +>(x: Vec<T>, y: Vec<U>) ... +``` + +If an associated type is bound in a generic type, then there should be spaces on +either side of the `=`: + +```rust +<T: Example<Item = u32>> +``` + +Prefer to use single-letter names for generic parameters. + + +### `where` clauses + +These rules apply for `where` clauses on any item. + +A `where` clause may immediately follow a closing bracket of any kind. +Otherwise, it must start a new line, with no indent. Each component of a `where` +clause must be on its own line and be block indented. There should be a trailing +comma, unless the clause is terminated with a semicolon. If the `where` clause +is followed by a block (or assignment), the block should be started on a new +line. Examples: + +```rust +fn function<T, U>(args) +where + T: Bound, + U: AnotherBound, +{ + body +} + +fn foo<T>( + args +) -> ReturnType +where + T: Bound, +{ + body +} + +fn foo<T, U>( + args, +) where + T: Bound, + U: AnotherBound, +{ + body +} + +fn foo<T, U>( + args +) -> ReturnType +where + T: Bound, + U: AnotherBound; // Note, no trailing comma. + +// Note that where clauses on `type` aliases are not enforced and should not +// be used. +type Foo<T> +where + T: Bound += Bar<T>; +``` + +If a `where` clause is very short, we recommend using an inline bound on the +type parameter. + + +If a component of a `where` clause is long, it may be broken before `+` and +further block indented. Each bound should go on its own line. E.g., + +```rust +impl<T: ?Sized, Idx> IndexRanges<Idx> for T +where + T: Index<Range<Idx>, Output = Self::Output> + + Index<RangeTo<Idx>, Output = Self::Output> + + Index<RangeFrom<Idx>, Output = Self::Output> + + Index<RangeInclusive<Idx>, Output = Self::Output> + + Index<RangeToInclusive<Idx>, Output = Self::Output> + Index<RangeFull> +``` + +#### Option - `where_single_line` + +`where_single_line` is `false` by default. If `true`, then a where clause with +exactly one component may be formatted on a single line if the rest of the +item's signature is also kept on one line. In this case, there is no need for a +trailing comma and if followed by a block, no need for a newline before the +block. E.g., + +```rust +// May be single-lined. +fn foo<T>(args) -> ReturnType +where T: Bound { + body +} + +// Must be multi-lined. +fn foo<T>( + args +) -> ReturnType +where + T: Bound, +{ + body +} +``` + + +### Type aliases + +Type aliases should generally be kept on one line. If necessary to break the +line, do so after the `=`; the right-hand-side should be block indented: + +```rust +pub type Foo = Bar<T>; + +// If multi-line is required +type VeryLongType<T, U: SomeBound> = + AnEvenLongerType<T, U, Foo<T>>; +``` + +Where possible avoid `where` clauses and keep type constraints inline. Where +that is not possible split the line before and after the `where` clause (and +split the `where` clause as normal), e.g., + +```rust +type VeryLongType<T, U> +where + T: U::AnAssociatedType, + U: SomeBound, += AnEvenLongerType<T, U, Foo<T>>; +``` + + +### Associated types + +Associated types should follow the guidelines above for type aliases. Where an +associated type has a bound, there should be a space after the colon but not +before: + +```rust +pub type Foo: Bar; +``` + + +### extern items + +When writing extern items (such as `extern "C" fn`), always be explicit about +the ABI. For example, write `extern "C" fn foo ...`, not `extern fn foo ...`, or +`extern "C" { ... }`. + + +### Imports (`use` statements) + +If an import can be formatted on one line, do so. There should be no spaces +around braces. + +```rust +use a::b::c; +use a::b::d::*; +use a::b::{foo, bar, baz}; +``` + + +#### Large list imports + +Prefer to use multiple imports rather than a multi-line import. However, tools +should not split imports by default (they may offer this as an option). + +If an import does require multiple lines (either because a list of single names +does not fit within the max width, or because of the rules for nested imports +below), then break after the opening brace and before the closing brace, use a +trailing comma, and block indent the names. + + +```rust +// Prefer +foo::{long, list, of, imports}; +foo::{more, imports}; + +// If necessary +foo::{ + long, list, of, imports, more, + imports, // Note trailing comma +}; +``` + + +#### Ordering of imports + +A *group* of imports is a set of imports on the same or sequential lines. One or +more blank lines or other items (e.g., a function) separate groups of imports. + +Within a group of imports, imports must be sorted ascii-betically. Groups of +imports must not be merged or re-ordered. + + +E.g., input: + +```rust +use d; +use c; + +use b; +use a; +``` + +output: + +```rust +use c; +use d; + +use a; +use b; +``` + +Because of `macro_use`, attributes must also start a new group and prevent +re-ordering. + +Note that tools which only have access to syntax (such as Rustfmt) cannot tell +which imports are from an external crate or the std lib, etc. + + +#### Ordering list import + +Names in a list import must be sorted ascii-betically, but with `self` and +`super` first, and groups and glob imports last. This applies recursively. For +example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g., +`use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`. + + +#### Normalisation + +Tools must make the following normalisations: + +* `use a::self;` -> `use a;` +* `use a::{};` -> (nothing) +* `use a::{b};` -> `use a::b;` + +And must apply these recursively. + +Tools must not otherwise merge or un-merge import lists or adjust glob imports +(without an explicit option). + + +#### Nested imports + +If there are any nested imports in a list import, then use the multi-line form, +even if the import fits on one line. Each nested import must be on its own line, +but non-nested imports must be grouped on as few lines as possible. + +For example, + +```rust +use a::b::{ + x, y, z, + u::{...}, + w::{...}, +}; +``` + + +#### Merging/un-merging imports + +An example: + +```rust +// Un-merged +use a::b; +use a::c::d; + +// Merged +use a::{b, c::d}; +``` + +Tools must not merge or un-merge imports by default. They may offer merging or +un-merging as an option. diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md new file mode 100644 index 000000000..b02b3c047 --- /dev/null +++ b/src/doc/style-guide/src/principles.md @@ -0,0 +1,51 @@ +# Guiding principles and rationale + +When deciding on style guidelines, the style team tried to be guided by the +following principles (in rough priority order): + +* readability + - scan-ability + - avoiding misleading formatting + - accessibility - readable and editable by users using the the widest + variety of hardware, including non-visual accessibility interfaces + - readability of code when quoted in rustc error messages + +* aesthetics + - sense of 'beauty' + - consistent with other languages/tools + +* specifics + - compatibility with version control practices - preserving diffs, + merge-friendliness, etc. + - preventing right-ward drift + - minimising vertical space + +* application + - ease of manual application + - ease of implementation (in Rustfmt, and in other tools/editors/code generators) + - internal consistency + - simplicity of formatting rules + + +## Overarching guidelines + +Prefer block indent over visual indent. E.g., + +```rust +// Block indent +a_function_call( + foo, + bar, +); + +// Visual indent +a_function_call(foo, + bar); +``` + +This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above +example) and less rightward drift. + +Lists should have a trailing comma when followed by a newline, see the block +indent example above. This choice makes moving code (e.g., by copy and paste) +easier and makes smaller diffs. diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md new file mode 100644 index 000000000..29b48bb1e --- /dev/null +++ b/src/doc/style-guide/src/statements.md @@ -0,0 +1,150 @@ +### Let statements + +There should be spaces after the `:` and on both sides of the `=` (if they are +present). No space before the semi-colon. + +```rust +// A comment. +let pattern: Type = expr; + +let pattern; +let pattern: Type; +let pattern = expr; +``` + +If possible the declaration should be formatted on a single line. If this is not +possible, then try splitting after the `=`, if the declaration can fit on two +lines. The expression should be block indented. + +```rust +let pattern: Type = + expr; +``` + +If the first line does not fit on a single line, then split after the colon, +using block indentation. If the type covers multiple lines, even after line- +breaking after the `:`, then the first line may be placed on the same line as +the `:`, subject to the [combining rules](https://github.com/rust-lang-nursery/fmt-rfcs/issues/61) (WIP). + + +```rust +let pattern: + Type = + expr; +``` + +e.g, + +```rust +let Foo { + f: abcd, + g: qwer, +}: Foo<Bar> = + Foo { f, g }; + +let (abcd, + defg): + Baz = +{ ... } +``` + +If the expression covers multiple lines, if the first line of the expression +fits in the remaining space, it stays on the same line as the `=`, the rest of the +expression is not indented. If the first line does not fit, then it should start +on the next lines, and should be block indented. If the expression is a block +and the type or pattern cover multiple lines, then the opening brace should be +on a new line and not indented (this provides separation for the interior of the +block from the type), otherwise the opening brace follows the `=`. + +Examples: + +```rust +let foo = Foo { + f: abcd, + g: qwer, +}; + +let foo = + ALongName { + f: abcd, + g: qwer, + }; + +let foo: Type = { + an_expression(); + ... +}; + +let foo: + ALongType = +{ + an_expression(); + ... +}; + +let Foo { + f: abcd, + g: qwer, +}: Foo<Bar> = Foo { + f: blimblimblim, + g: blamblamblam, +}; + +let Foo { + f: abcd, + g: qwer, +}: Foo<Bar> = foo( + blimblimblim, + blamblamblam, +); +``` + + +### Macros in statement position + +A macro use in statement position should use parentheses or square brackets as +delimiters and should be terminated with a semi-colon. There should be no spaces +between the name, `!`, the delimiters, or the `;`. + +```rust +// A comment. +a_macro!(...); +``` + + +### Expressions in statement position + +There should be no space between the expression and the semi-colon. + +``` +<expr>; +``` + +All expressions in statement position should be terminated with a semi-colon, +unless they end with a block or are used as the value for a block. + +E.g., + +```rust +{ + an_expression(); + expr_as_value() +} + +return foo(); + +loop { + break; +} +``` + +Use a semi-colon where an expression has void type, even if it could be +propagated. E.g., + +```rust +fn foo() { ... } + +fn bar() { + foo(); +} +``` diff --git a/src/doc/style-guide/src/types.md b/src/doc/style-guide/src/types.md new file mode 100644 index 000000000..25861ddab --- /dev/null +++ b/src/doc/style-guide/src/types.md @@ -0,0 +1,58 @@ +## Types and Bounds + +### Single line formatting + +* `[T]` no spaces +* `[T; expr]`, e.g., `[u32; 42]`, `[Vec<Foo>; 10 * 2 + foo()]` (space after colon, no spaces around square brackets) +* `*const T`, `*mut T` (no space after `*`, space before type) +* `&'a T`, `&T`, `&'a mut T`, `&mut T` (no space after `&`, single spaces separating other words) +* `unsafe extern "C" fn<'a, 'b, 'c>(T, U, V) -> W` or `fn()` (single spaces around keyowrds and sigils, and after commas, no trailing commas, no spaces around brackets) +* `!` should be treated like any other type name, `Name` +* `(A, B, C, D)` (spaces after commas, no spaces around parens, no trailing comma unless it is a one-tuple) +* `<Baz<T> as SomeTrait>::Foo::Bar` or `Foo::Bar` or `::Foo::Bar` (no spaces around `::` or angle brackets, single spaces around `as`) +* `Foo::Bar<T, U, V>` (spaces after commas, no trailing comma, no spaces around angle brackets) +* `T + T + T` (single spaces between types, and `+`). +* `impl T + T + T` (single spaces between keyword, types, and `+`). + +Parentheses used in types should not be surrounded by whitespace, e.g., `(Foo)` + + +### Line breaks + +Avoid breaking lines in types where possible. Prefer breaking at outermost scope, e.g., prefer + +```rust +Foo< + Bar, + Baz<Type1, Type2>, +> +``` + +to + +```rust +Foo<Bar, Baz< + Type1, + Type2, +>> +``` + +`[T; expr]` may be broken after the `;` if necessary. + +Function types may be broken following the rules for function declarations. + +Generic types may be broken following the rules for generics. + +Types with `+` may be broken after any `+` using block indent and breaking before the `+`. When breaking such a type, all `+`s should be line broken, e.g., + +```rust +impl Clone + + Copy + + Debug + +Box< + Clone + + Copy + + Debug +> +``` |