Skip to main content

rustfmt_nightly/config/
options.rs

1#![allow(unused_imports)]
2
3use std::collections::{HashSet, hash_set};
4use std::fmt;
5use std::path::{Path, PathBuf};
6use std::str::FromStr;
7
8use itertools::Itertools;
9use rustfmt_config_proc_macro::config_type;
10use serde::de::{SeqAccess, Visitor};
11use serde::ser::SerializeSeq;
12use serde::{Deserialize, Deserializer, Serialize, Serializer};
13
14use crate::config::Config;
15use crate::config::file_lines::FileLines;
16use crate::config::lists::*;
17use crate::config::macro_names::MacroSelectors;
18
19#[config_type]
20pub enum NewlineStyle {
21    /// Auto-detect based on the raw source input.
22    Auto,
23    /// Force CRLF (`\r\n`).
24    Windows,
25    /// Force CR (`\n`).
26    Unix,
27    /// `\r\n` in Windows, `\n` on other platforms.
28    Native,
29}
30
31#[config_type]
32/// Where to put the opening brace of items (`fn`, `impl`, etc.).
33pub enum BraceStyle {
34    /// Put the opening brace on the next line.
35    AlwaysNextLine,
36    /// Put the opening brace on the same line, if possible.
37    PreferSameLine,
38    /// Prefer the same line except where there is a where-clause, in which
39    /// case force the brace to be put on the next line.
40    SameLineWhere,
41}
42
43#[config_type]
44/// Where to put the opening brace of conditional expressions (`if`, `match`, etc.).
45pub enum ControlBraceStyle {
46    /// K&R style, Rust community default
47    AlwaysSameLine,
48    /// Stroustrup style
49    ClosingNextLine,
50    /// Allman style
51    AlwaysNextLine,
52}
53
54#[config_type]
55/// How to indent.
56pub enum IndentStyle {
57    /// First line on the same line as the opening brace, all lines aligned with
58    /// the first line.
59    Visual,
60    /// First line is on a new line and all lines align with **block** indent.
61    Block,
62}
63
64#[config_type]
65/// How to place a list-like items.
66/// FIXME: Issue-3581: this should be renamed to ItemsLayout when publishing 2.0
67pub enum Density {
68    /// Fit as much on one line as possible.
69    Compressed,
70    /// Items are placed horizontally if sufficient space, vertically otherwise.
71    Tall,
72    /// Place every item on a separate line.
73    Vertical,
74}
75
76#[config_type]
77/// Spacing around type combinators.
78pub enum TypeDensity {
79    /// No spaces around "=" and "+"
80    Compressed,
81    /// Spaces around " = " and " + "
82    Wide,
83}
84
85#[config_type]
86/// Heuristic settings that can be used to simply
87/// the configuration of the granular width configurations
88/// like `struct_lit_width`, `array_width`, etc.
89pub enum Heuristics {
90    /// Turn off any heuristics
91    Off,
92    /// Turn on max heuristics
93    Max,
94    /// Use scaled values based on the value of `max_width`
95    Default,
96}
97
98#[config_type]
99/// Heuristic settings for doc comments. Same as `Heuristics`, but `Inherit` will inherit the value
100/// from the top-level configuration.
101pub enum DocCodeHeuristics {
102    /// Inherit from the top-level configuration
103    Inherit,
104    /// Turn off any heuristics
105    Off,
106    /// Turn on max heuristics
107    Max,
108    /// Use scaled values based on the value of `max_width`
109    Default,
110}
111
112impl DocCodeHeuristics {
113    pub fn to_heuristics(self) -> Option<Heuristics> {
114        match self {
115            DocCodeHeuristics::Inherit => None,
116            DocCodeHeuristics::Off => Some(Heuristics::Off),
117            DocCodeHeuristics::Max => Some(Heuristics::Max),
118            DocCodeHeuristics::Default => Some(Heuristics::Default),
119        }
120    }
121}
122
123impl Density {
124    pub fn to_list_tactic(self, style_edition: StyleEdition, len: usize) -> ListTactic {
125        match self {
126            Density::Compressed => ListTactic::Mixed,
127            Density::Tall => ListTactic::HorizontalVertical,
128            Density::Vertical if len == 1 => {
129                if style_edition <= StyleEdition::Edition2024 {
130                    ListTactic::Horizontal
131                } else {
132                    ListTactic::HorizontalVertical
133                }
134            }
135            Density::Vertical => ListTactic::Vertical,
136        }
137    }
138}
139
140#[config_type]
141/// Configuration for import groups, i.e. sets of imports separated by newlines.
142pub enum GroupImportsTactic {
143    /// Keep groups as they are.
144    Preserve,
145    /// Discard existing groups, and create new groups for
146    ///  1. `std` / `core` / `alloc` imports
147    ///  2. other imports
148    ///  3. `self` / `crate` / `super` imports
149    StdExternalCrate,
150    /// Discard existing groups, and create a single group for everything
151    One,
152}
153
154#[config_type]
155/// How to merge imports.
156pub enum ImportGranularity {
157    /// Do not merge imports.
158    Preserve,
159    /// Use one `use` statement per crate.
160    Crate,
161    /// Use one `use` statement per module.
162    Module,
163    /// Use one `use` statement per imported item.
164    Item,
165    /// Use one `use` statement including all items.
166    One,
167}
168
169/// Controls how rustfmt should handle case in hexadecimal literals.
170#[config_type]
171pub enum HexLiteralCase {
172    /// Leave the literal as-is
173    Preserve,
174    /// Ensure all literals use uppercase lettering
175    Upper,
176    /// Ensure all literals use lowercase lettering
177    Lower,
178}
179
180/// How to treat trailing zeros in floating-point literals.
181#[config_type]
182pub enum FloatLiteralTrailingZero {
183    /// Leave the literal as-is.
184    Preserve,
185    /// Add a trailing zero to the literal.
186    Always,
187    /// Add a trailing zero by default. If the literal contains an exponent or a suffix, the zero
188    /// and the preceding period are removed.
189    IfNoPostfix,
190    /// Remove the trailing zero. If the literal contains an exponent or a suffix, the preceding
191    /// period is also removed.
192    Never,
193}
194
195#[config_type]
196pub enum ReportTactic {
197    Always,
198    Unnumbered,
199    Never,
200}
201
202/// What Rustfmt should emit. Mostly corresponds to the `--emit` command line
203/// option.
204#[config_type]
205pub enum EmitMode {
206    /// Emits to files.
207    Files,
208    /// Writes the output to stdout.
209    Stdout,
210    /// Displays how much of the input file was processed
211    Coverage,
212    /// Unfancy stdout
213    Checkstyle,
214    /// Writes the resulting diffs in a JSON format. Returns an empty array
215    /// `[]` if there were no diffs.
216    Json,
217    /// Output the changed lines (for internal value only)
218    ModifiedLines,
219    /// Checks if a diff can be generated. If so, rustfmt outputs a diff and
220    /// quits with exit code 1.
221    /// This option is designed to be run in CI where a non-zero exit signifies
222    /// non-standard code formatting. Used for `--check`.
223    Diff,
224}
225
226/// Client-preference for coloured output.
227#[config_type]
228pub enum Color {
229    /// Always use color, whether it is a piped or terminal output
230    Always,
231    /// Never use color
232    Never,
233    /// Automatically use color, if supported by terminal
234    Auto,
235}
236
237#[config_type]
238/// rustfmt format style version.
239pub enum Version {
240    /// 1.x.y. When specified, rustfmt will format in the same style as 1.0.0.
241    One,
242    /// 2.x.y. When specified, rustfmt will format in the latest style.
243    Two,
244}
245
246impl Color {
247    /// Whether we should use a coloured terminal.
248    pub fn use_colored_tty(self) -> bool {
249        match self {
250            Color::Always | Color::Auto => true,
251            Color::Never => false,
252        }
253    }
254}
255
256/// How chatty should Rustfmt be?
257#[config_type]
258pub enum Verbosity {
259    /// Emit more.
260    Verbose,
261    /// Default.
262    Normal,
263    /// Emit as little as possible.
264    Quiet,
265}
266
267#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
268pub struct WidthHeuristics {
269    // Maximum width of the args of a function call before falling back
270    // to vertical formatting.
271    pub(crate) fn_call_width: usize,
272    // Maximum width of the args of a function-like attributes before falling
273    // back to vertical formatting.
274    pub(crate) attr_fn_like_width: usize,
275    // Maximum width in the body of a struct lit before falling back to
276    // vertical formatting.
277    pub(crate) struct_lit_width: usize,
278    // Maximum width in the body of a struct variant before falling back
279    // to vertical formatting.
280    pub(crate) struct_variant_width: usize,
281    // Maximum width of an array literal before falling back to vertical
282    // formatting.
283    pub(crate) array_width: usize,
284    // Maximum length of a chain to fit on a single line.
285    pub(crate) chain_width: usize,
286    // Maximum line length for single line if-else expressions. A value
287    // of zero means always break if-else expressions.
288    pub(crate) single_line_if_else_max_width: usize,
289    // Maximum line length for single line let-else statements. A value of zero means
290    // always format the divergent `else` block over multiple lines.
291    pub(crate) single_line_let_else_max_width: usize,
292}
293
294impl fmt::Display for WidthHeuristics {
295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296        write!(f, "{self:?}")
297    }
298}
299
300impl WidthHeuristics {
301    // Using this WidthHeuristics means we ignore heuristics.
302    pub fn null() -> WidthHeuristics {
303        WidthHeuristics {
304            fn_call_width: usize::MAX,
305            attr_fn_like_width: usize::MAX,
306            struct_lit_width: 0,
307            struct_variant_width: 0,
308            array_width: usize::MAX,
309            chain_width: usize::MAX,
310            single_line_if_else_max_width: 0,
311            single_line_let_else_max_width: 0,
312        }
313    }
314
315    pub fn set(max_width: usize) -> WidthHeuristics {
316        WidthHeuristics {
317            fn_call_width: max_width,
318            attr_fn_like_width: max_width,
319            struct_lit_width: max_width,
320            struct_variant_width: max_width,
321            array_width: max_width,
322            chain_width: max_width,
323            single_line_if_else_max_width: max_width,
324            single_line_let_else_max_width: max_width,
325        }
326    }
327
328    // scale the default WidthHeuristics according to max_width
329    pub fn scaled(max_width: usize) -> WidthHeuristics {
330        const DEFAULT_MAX_WIDTH: usize = 100;
331        let max_width_ratio = if max_width > DEFAULT_MAX_WIDTH {
332            let ratio = max_width as f32 / DEFAULT_MAX_WIDTH as f32;
333            // round to the closest 0.1
334            (ratio * 10.0).round() / 10.0
335        } else {
336            1.0
337        };
338        WidthHeuristics {
339            fn_call_width: (60.0 * max_width_ratio).round() as usize,
340            attr_fn_like_width: (70.0 * max_width_ratio).round() as usize,
341            struct_lit_width: (18.0 * max_width_ratio).round() as usize,
342            struct_variant_width: (35.0 * max_width_ratio).round() as usize,
343            array_width: (60.0 * max_width_ratio).round() as usize,
344            chain_width: (60.0 * max_width_ratio).round() as usize,
345            single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
346            single_line_let_else_max_width: (50.0 * max_width_ratio).round() as usize,
347        }
348    }
349}
350
351impl ::std::str::FromStr for WidthHeuristics {
352    type Err = &'static str;
353
354    fn from_str(_: &str) -> Result<Self, Self::Err> {
355        Err("WidthHeuristics is not parsable")
356    }
357}
358
359impl Default for EmitMode {
360    fn default() -> EmitMode {
361        EmitMode::Files
362    }
363}
364
365/// A set of directories, files and modules that rustfmt should ignore.
366#[derive(Default, Clone, Debug, PartialEq)]
367pub struct IgnoreList {
368    /// A set of path specified in rustfmt.toml.
369    path_set: HashSet<PathBuf>,
370    /// A path to rustfmt.toml.
371    rustfmt_toml_path: PathBuf,
372}
373
374impl fmt::Display for IgnoreList {
375    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376        write!(
377            f,
378            "[{}]",
379            self.path_set
380                .iter()
381                .format_with(", ", |path, f| f(&format_args!(
382                    "{}",
383                    path.to_string_lossy()
384                )))
385        )
386    }
387}
388
389impl Serialize for IgnoreList {
390    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
391    where
392        S: Serializer,
393    {
394        let mut seq = serializer.serialize_seq(Some(self.path_set.len()))?;
395        for e in &self.path_set {
396            seq.serialize_element(e)?;
397        }
398        seq.end()
399    }
400}
401
402impl<'de> Deserialize<'de> for IgnoreList {
403    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
404    where
405        D: Deserializer<'de>,
406    {
407        struct HashSetVisitor;
408        impl<'v> Visitor<'v> for HashSetVisitor {
409            type Value = HashSet<PathBuf>;
410
411            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
412                formatter.write_str("a sequence of path")
413            }
414
415            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
416            where
417                A: SeqAccess<'v>,
418            {
419                let mut path_set = HashSet::new();
420                while let Some(elem) = seq.next_element()? {
421                    path_set.insert(elem);
422                }
423                Ok(path_set)
424            }
425        }
426        Ok(IgnoreList {
427            path_set: deserializer.deserialize_seq(HashSetVisitor)?,
428            rustfmt_toml_path: PathBuf::new(),
429        })
430    }
431}
432
433impl<'a> IntoIterator for &'a IgnoreList {
434    type Item = &'a PathBuf;
435    type IntoIter = hash_set::Iter<'a, PathBuf>;
436
437    fn into_iter(self) -> Self::IntoIter {
438        self.path_set.iter()
439    }
440}
441
442impl IgnoreList {
443    pub fn add_prefix(&mut self, dir: &Path) {
444        self.rustfmt_toml_path = dir.to_path_buf();
445    }
446
447    pub fn rustfmt_toml_path(&self) -> &Path {
448        &self.rustfmt_toml_path
449    }
450}
451
452impl FromStr for IgnoreList {
453    type Err = &'static str;
454
455    fn from_str(_: &str) -> Result<Self, Self::Err> {
456        Err("IgnoreList is not parsable")
457    }
458}
459
460/// Maps client-supplied options to Rustfmt's internals, mostly overriding
461/// values in a config with values from the command line.
462pub trait CliOptions {
463    fn apply_to(self, config: &mut Config);
464
465    /// It is ok if the returned path doesn't exist or is not canonicalized
466    /// (i.e. the callers are expected to handle such cases).
467    fn config_path(&self) -> Option<&Path>;
468    fn edition(&self) -> Option<Edition>;
469    fn style_edition(&self) -> Option<StyleEdition>;
470    fn version(&self) -> Option<Version>;
471}
472
473/// The edition of the syntax and semantics of code (RFC 2052).
474#[config_type]
475pub enum Edition {
476    #[value = "2015"]
477    #[doc_hint = "2015"]
478    /// Edition 2015.
479    Edition2015,
480    #[value = "2018"]
481    #[doc_hint = "2018"]
482    /// Edition 2018.
483    Edition2018,
484    #[value = "2021"]
485    #[doc_hint = "2021"]
486    /// Edition 2021.
487    Edition2021,
488    #[value = "2024"]
489    #[doc_hint = "2024"]
490    /// Edition 2024.
491    Edition2024,
492}
493
494impl Default for Edition {
495    fn default() -> Edition {
496        Edition::Edition2015
497    }
498}
499
500impl From<Edition> for rustc_span::edition::Edition {
501    fn from(edition: Edition) -> Self {
502        match edition {
503            Edition::Edition2015 => Self::Edition2015,
504            Edition::Edition2018 => Self::Edition2018,
505            Edition::Edition2021 => Self::Edition2021,
506            Edition::Edition2024 => Self::Edition2024,
507        }
508    }
509}
510
511impl From<Edition> for StyleEdition {
512    fn from(edition: Edition) -> Self {
513        match edition {
514            Edition::Edition2015 => StyleEdition::Edition2015,
515            Edition::Edition2018 => StyleEdition::Edition2018,
516            Edition::Edition2021 => StyleEdition::Edition2021,
517            Edition::Edition2024 => StyleEdition::Edition2024,
518        }
519    }
520}
521
522impl PartialOrd for Edition {
523    fn partial_cmp(&self, other: &Edition) -> Option<std::cmp::Ordering> {
524        rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
525    }
526}
527
528/// Controls how rustfmt should handle leading pipes on match arms.
529#[config_type]
530pub enum MatchArmLeadingPipe {
531    /// Place leading pipes on all match arms
532    Always,
533    /// Never emit leading pipes on match arms
534    Never,
535    /// Preserve any existing leading pipes
536    Preserve,
537}
538
539/// Defines the default values for each config according to the edition of the
540/// [Style Guide] as per [RFC 3338]. Rustfmt output may differ between Style editions.
541///
542/// [Style Guide]: https://doc.rust-lang.org/nightly/style-guide/
543/// [RFC 3338]: https://rust-lang.github.io/rfcs/3338-style-evolution.html
544#[config_type]
545pub enum StyleEdition {
546    #[value = "2015"]
547    #[doc_hint = "2015"]
548    /// [Edition 2015]()
549    Edition2015,
550    #[value = "2018"]
551    #[doc_hint = "2018"]
552    /// [Edition 2018]()
553    Edition2018,
554    #[value = "2021"]
555    #[doc_hint = "2021"]
556    /// [Edition 2021]()
557    Edition2021,
558    #[value = "2024"]
559    #[doc_hint = "2024"]
560    /// [Edition 2024]().
561    Edition2024,
562    #[value = "2027"]
563    #[doc_hint = "2027"]
564    #[unstable_variant]
565    /// [Edition 2027]().
566    Edition2027,
567}
568
569impl From<StyleEdition> for rustc_span::edition::Edition {
570    fn from(edition: StyleEdition) -> Self {
571        match edition {
572            StyleEdition::Edition2015 => Self::Edition2015,
573            StyleEdition::Edition2018 => Self::Edition2018,
574            StyleEdition::Edition2021 => Self::Edition2021,
575            StyleEdition::Edition2024 => Self::Edition2024,
576            // TODO: should update to Edition2027 when it becomes available
577            StyleEdition::Edition2027 => Self::Edition2024,
578        }
579    }
580}
581
582impl PartialOrd for StyleEdition {
583    fn partial_cmp(&self, other: &StyleEdition) -> Option<std::cmp::Ordering> {
584        // FIXME(ytmimi): Update `StyleEdition::Edition2027` logic when
585        // `rustc_span::edition::Edition::Edition2027` becomes available in the compiler
586        match (self, other) {
587            (Self::Edition2027, Self::Edition2027) => Some(std::cmp::Ordering::Equal),
588            (_, Self::Edition2027) => Some(std::cmp::Ordering::Less),
589            (Self::Edition2027, _) => Some(std::cmp::Ordering::Greater),
590            (Self::Edition2015 | Self::Edition2018 | Self::Edition2021 | Self::Edition2024, _) => {
591                rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
592            }
593        }
594    }
595}
596
597/// Defines unit structs to implement `StyleEditionDefault` for.
598#[macro_export]
599macro_rules! config_option_with_style_edition_default {
600    ($name:ident, $config_ty:ty, _ => $default:expr) => {
601        #[allow(unreachable_pub)]
602        pub struct $name;
603        $crate::style_edition_default!($name, $config_ty, _ => $default);
604    };
605    ($name:ident, $config_ty:ty, Edition2024 => $default_2024:expr, _ => $default_2015:expr) => {
606        pub struct $name;
607        $crate::style_edition_default!(
608            $name,
609            $config_ty,
610            Edition2024 => $default_2024,
611            _ => $default_2015
612        );
613    };
614    (
615        $($name:ident, $config_ty:ty, $(Edition2024 => $default_2024:expr,)? _ => $default:expr);*
616        $(;)*
617    ) => {
618        $(
619            config_option_with_style_edition_default!(
620                $name, $config_ty, $(Edition2024 => $default_2024,)? _ => $default
621            );
622        )*
623    };
624}
625
626// TODO(ytmimi) Some of the configuration values have a `Config` suffix, while others don't.
627// I chose to add a `Config` suffix in cases where a type for the config option was already
628// defined. For example, `NewlineStyle` and `NewlineStyleConfig`. There was some discussion
629// about using the `Config` suffix more consistently.
630config_option_with_style_edition_default!(
631    // Fundamental stuff
632    MaxWidth, usize, _ => 100;
633    HardTabs, bool, _ => false;
634    TabSpaces, usize, _ => 4;
635    NewlineStyleConfig, NewlineStyle, _ => NewlineStyle::Auto;
636    IndentStyleConfig, IndentStyle, _ => IndentStyle::Block;
637
638    // Width Heuristics
639    UseSmallHeuristics, Heuristics, _ => Heuristics::Default;
640    WidthHeuristicsConfig, WidthHeuristics, _ => WidthHeuristics::scaled(100);
641    FnCallWidth, usize, _ => 60;
642    AttrFnLikeWidth, usize, _ => 70;
643    StructLitWidth, usize, _ => 18;
644    StructVariantWidth, usize, _ => 35;
645    ArrayWidth, usize, _ => 60;
646    ChainWidth, usize, _ => 60;
647    SingleLineIfElseMaxWidth, usize, _ => 50;
648    SingleLineLetElseMaxWidth, usize, _ => 50;
649
650    // Comments. macros, and strings
651    WrapComments, bool, _ => false;
652    FormatCodeInDocComments, bool, _ => false;
653    DocCommentCodeBlockWidth, usize, _ => 100;
654    DocUseSmallHeuristics, DocCodeHeuristics, _ => DocCodeHeuristics::Inherit;
655    CommentWidth, usize, _ => 80;
656    NormalizeComments, bool, _ => false;
657    NormalizeDocAttributes, bool, _ => false;
658    FormatStrings, bool, _ => false;
659    FormatMacroMatchers, bool, _ => false;
660    FormatMacroBodies, bool, _ => true;
661    SkipMacroInvocations, MacroSelectors, _ => MacroSelectors::default();
662    HexLiteralCaseConfig, HexLiteralCase, _ => HexLiteralCase::Preserve;
663    FloatLiteralTrailingZeroConfig, FloatLiteralTrailingZero, _ =>
664        FloatLiteralTrailingZero::Preserve;
665
666    // Single line expressions and items
667    EmptyItemSingleLine, bool, _ => true;
668    StructLitSingleLine, bool, _ => true;
669    FnSingleLine, bool, _ => false;
670    WhereSingleLine, bool, _ => false;
671
672    // Imports
673    ImportsIndent, IndentStyle, _ => IndentStyle::Block;
674    ImportsLayout, ListTactic, _ => ListTactic::Mixed;
675    ImportsGranularityConfig, ImportGranularity, _ => ImportGranularity::Preserve;
676    GroupImportsTacticConfig, GroupImportsTactic, _ => GroupImportsTactic::Preserve;
677    MergeImports, bool, _ => false;
678
679    // Ordering
680    ReorderImports, bool, _ => true;
681    ReorderModules, bool, _ => true;
682    ReorderImplItems, bool, _ => false;
683
684    // Spaces around punctuation
685    TypePunctuationDensity, TypeDensity, _ => TypeDensity::Wide;
686    SpaceBeforeColon, bool, _ => false;
687    SpaceAfterColon, bool, _ => true;
688    SpacesAroundRanges, bool, _ => false;
689    BinopSeparator, SeparatorPlace, _ => SeparatorPlace::Front;
690
691    // Misc.
692    RemoveNestedParens, bool, _ => true;
693    CombineControlExpr, bool, _ => true;
694    ShortArrayElementWidthThreshold, usize, _ => 10;
695    OverflowDelimitedExpr, bool, _ => false;
696    StructFieldAlignThreshold, usize, _ => 0;
697    EnumDiscrimAlignThreshold, usize, _ => 0;
698    MatchArmBlocks, bool, _ => true;
699    MatchArmLeadingPipeConfig, MatchArmLeadingPipe, _ => MatchArmLeadingPipe::Never;
700    MatchArmIndent, bool, _ => true;
701    ForceMultilineBlocks, bool, _ => false;
702    FnArgsLayout, Density, _ => Density::Tall;
703    FnParamsLayout, Density, _ => Density::Tall;
704    BraceStyleConfig, BraceStyle, _ => BraceStyle::SameLineWhere;
705    ControlBraceStyleConfig, ControlBraceStyle, _ => ControlBraceStyle::AlwaysSameLine;
706    TrailingSemicolon, bool, _ => true;
707    TrailingComma, SeparatorTactic, _ => SeparatorTactic::Vertical;
708    MatchBlockTrailingComma, bool, _ => false;
709    BlankLinesUpperBound, usize, _ => 1;
710    BlankLinesLowerBound, usize, _ => 0;
711    EditionConfig, Edition, _ => Edition::Edition2015;
712    StyleEditionConfig, StyleEdition,
713        Edition2024 => StyleEdition::Edition2024, _ => StyleEdition::Edition2015;
714    VersionConfig, Version, Edition2024 => Version::Two, _ => Version::One;
715    InlineAttributeWidth, usize, _ => 0;
716    FormatGeneratedFiles, bool, _ => true;
717    GeneratedMarkerLineSearchLimit, usize, _ => 5;
718
719    // Options that can change the source code beyond whitespace/blocks (somewhat linty things)
720    MergeDerives, bool, _ => true;
721    UseTryShorthand, bool, _ => false;
722    UseFieldInitShorthand, bool, _ => false;
723    ForceExplicitAbi, bool, _ => true;
724    CondenseWildcardSuffixes, bool, _ => false;
725
726    // Control options (changes the operation of rustfmt, rather than the formatting)
727    ColorConfig, Color, _ => Color::Auto;
728    RequiredVersion, String, _ => env!("CARGO_PKG_VERSION").to_owned();
729    UnstableFeatures, bool, _ => false;
730    DisableAllFormatting, bool, _ => false;
731    SkipChildren, bool, _ => false;
732    HideParseErrors, bool, _ => false;
733    ShowParseErrors, bool, _ => true;
734    ErrorOnLineOverflow, bool, _ => false;
735    ErrorOnUnformatted, bool, _ => false;
736    Ignore, IgnoreList, _ => IgnoreList::default();
737
738    // Not user-facing
739    Verbose, Verbosity, _ => Verbosity::Normal;
740    FileLinesConfig, FileLines, _ => FileLines::all();
741    EmitModeConfig, EmitMode, _ => EmitMode::Files;
742    MakeBackup, bool, _ => false;
743    PrintMisformattedFileNames, bool, _ => false;
744);
745
746#[test]
747fn style_edition_comparisons() {
748    // Style Edition 2015
749    assert!(StyleEdition::Edition2015 == StyleEdition::Edition2015);
750    assert!(StyleEdition::Edition2015 < StyleEdition::Edition2018);
751    assert!(StyleEdition::Edition2015 < StyleEdition::Edition2021);
752    assert!(StyleEdition::Edition2015 < StyleEdition::Edition2024);
753    assert!(StyleEdition::Edition2015 < StyleEdition::Edition2027);
754
755    // Style Edition 2018
756    assert!(StyleEdition::Edition2018 > StyleEdition::Edition2015);
757    assert!(StyleEdition::Edition2018 == StyleEdition::Edition2018);
758    assert!(StyleEdition::Edition2018 < StyleEdition::Edition2021);
759    assert!(StyleEdition::Edition2018 < StyleEdition::Edition2024);
760    assert!(StyleEdition::Edition2018 < StyleEdition::Edition2027);
761
762    // Style Edition 2021
763    assert!(StyleEdition::Edition2021 > StyleEdition::Edition2015);
764    assert!(StyleEdition::Edition2021 > StyleEdition::Edition2018);
765    assert!(StyleEdition::Edition2021 == StyleEdition::Edition2021);
766    assert!(StyleEdition::Edition2021 < StyleEdition::Edition2024);
767    assert!(StyleEdition::Edition2021 < StyleEdition::Edition2027);
768
769    // Style Edition 2024
770    assert!(StyleEdition::Edition2024 > StyleEdition::Edition2015);
771    assert!(StyleEdition::Edition2024 > StyleEdition::Edition2018);
772    assert!(StyleEdition::Edition2024 > StyleEdition::Edition2021);
773    assert!(StyleEdition::Edition2024 == StyleEdition::Edition2024);
774    assert!(StyleEdition::Edition2024 < StyleEdition::Edition2027);
775
776    // Style Edition 2024
777    assert!(StyleEdition::Edition2027 > StyleEdition::Edition2015);
778    assert!(StyleEdition::Edition2027 > StyleEdition::Edition2018);
779    assert!(StyleEdition::Edition2027 > StyleEdition::Edition2021);
780    assert!(StyleEdition::Edition2027 > StyleEdition::Edition2024);
781    assert!(StyleEdition::Edition2027 == StyleEdition::Edition2027);
782}