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