1use crate::config::file_lines::FileLines;
2use crate::config::macro_names::MacroSelectors;
3use crate::config::options::{IgnoreList, WidthHeuristics};
4
5pub(crate) trait ConfigType: Sized {
7 fn doc_hint() -> String;
10
11 fn stable_variant(&self) -> bool {
16 true
17 }
18}
19
20impl ConfigType for bool {
21 fn doc_hint() -> String {
22 String::from("<boolean>")
23 }
24}
25
26impl ConfigType for usize {
27 fn doc_hint() -> String {
28 String::from("<unsigned integer>")
29 }
30}
31
32impl ConfigType for isize {
33 fn doc_hint() -> String {
34 String::from("<signed integer>")
35 }
36}
37
38impl ConfigType for String {
39 fn doc_hint() -> String {
40 String::from("<string>")
41 }
42}
43
44impl ConfigType for FileLines {
45 fn doc_hint() -> String {
46 String::from("<json>")
47 }
48}
49
50impl ConfigType for MacroSelectors {
51 fn doc_hint() -> String {
52 String::from("[<string>, ...]")
53 }
54}
55
56impl ConfigType for WidthHeuristics {
57 fn doc_hint() -> String {
58 String::new()
59 }
60}
61
62impl ConfigType for IgnoreList {
63 fn doc_hint() -> String {
64 String::from("[<string>,..]")
65 }
66}
67
68macro_rules! create_config {
69 ($($i:ident: $ty:ty, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => (
76 #[cfg(test)]
77 use std::collections::HashSet;
78 use std::io::Write;
79
80 use serde::{Deserialize, Serialize};
81 use $crate::config::style_edition::StyleEditionDefault;
82
83 #[derive(Clone)]
84 #[allow(unreachable_pub)]
85 pub struct Config {
86 $($i: (Cell<bool>, bool, <$ty as StyleEditionDefault>::ConfigType, bool, bool)),+
96 }
97
98 #[derive(Deserialize, Serialize, Clone)]
104 #[allow(unreachable_pub)]
105 pub struct PartialConfig {
106 $(pub $i: Option<<$ty as StyleEditionDefault>::ConfigType>),+
107 }
108
109 #[allow(unreachable_pub)]
115 pub struct ConfigSetter<'a>(&'a mut Config);
116
117 impl<'a> ConfigSetter<'a> {
118 $(
119 #[allow(unreachable_pub)]
120 pub fn $i(&mut self, value: <$ty as StyleEditionDefault>::ConfigType) {
121 (self.0).$i.2 = value;
122 match stringify!($i) {
123 "max_width"
124 | "use_small_heuristics"
125 | "fn_call_width"
126 | "single_line_if_else_max_width"
127 | "single_line_let_else_max_width"
128 | "attr_fn_like_width"
129 | "struct_lit_width"
130 | "struct_variant_width"
131 | "array_width"
132 | "chain_width" => self.0.set_heuristics(),
133 "merge_imports" => self.0.set_merge_imports(),
134 "fn_args_layout" => self.0.set_fn_args_layout(),
135 "hide_parse_errors" => self.0.set_hide_parse_errors(),
136 "version" => self.0.set_version(),
137 &_ => (),
138 }
139 }
140 )+
141 }
142
143 #[allow(unreachable_pub)]
144 pub struct CliConfigSetter<'a>(&'a mut Config);
145
146 impl<'a> CliConfigSetter<'a> {
147 $(
148 #[allow(unreachable_pub)]
149 pub fn $i(&mut self, value: <$ty as StyleEditionDefault>::ConfigType) {
150 (self.0).$i.2 = value;
151 (self.0).$i.4 = true;
152 match stringify!($i) {
153 "max_width"
154 | "use_small_heuristics"
155 | "fn_call_width"
156 | "single_line_if_else_max_width"
157 | "single_line_let_else_max_width"
158 | "attr_fn_like_width"
159 | "struct_lit_width"
160 | "struct_variant_width"
161 | "array_width"
162 | "chain_width" => self.0.set_heuristics(),
163 "merge_imports" => self.0.set_merge_imports(),
164 "fn_args_layout" => self.0.set_fn_args_layout(),
165 "hide_parse_errors" => self.0.set_hide_parse_errors(),
166 "version" => self.0.set_version(),
167 &_ => (),
168 }
169 }
170 )+
171 }
172
173 #[allow(unreachable_pub)]
176 pub struct ConfigWasSet<'a>(&'a Config);
177
178 impl<'a> ConfigWasSet<'a> {
179 $(
180 #[allow(unreachable_pub)]
181 pub fn $i(&self) -> bool {
182 (self.0).$i.1
183 }
184 )+
185 }
186
187 #[allow(unreachable_pub)]
190 pub struct CliConfigWasSet<'a>(&'a Config);
191
192 impl<'a> CliConfigWasSet<'a> {
193 $(
194 #[allow(unreachable_pub)]
195 pub fn $i(&self) -> bool {
196 (self.0).$i.4
197 }
198 )+
199 }
200
201 impl Config {
202 $(
203 #[allow(unreachable_pub)]
204 pub fn $i(&self) -> <$ty as StyleEditionDefault>::ConfigType {
205 self.$i.0.set(true);
206 self.$i.2.clone()
207 }
208 )+
209
210 #[allow(unreachable_pub)]
211 pub(super) fn default_with_style_edition(style_edition: StyleEdition) -> Config {
212 Config {
213 $(
214 $i: (
215 Cell::new(false),
216 false,
217 <$ty as StyleEditionDefault>::style_edition_default(
218 style_edition
219 ),
220 $stb,
221 false,
222 ),
223 )+
224 }
225 }
226
227 #[allow(unreachable_pub)]
228 pub fn set(&mut self) -> ConfigSetter<'_> {
229 ConfigSetter(self)
230 }
231
232 #[allow(unreachable_pub)]
233 pub fn set_cli(&mut self) -> CliConfigSetter<'_> {
234 CliConfigSetter(self)
235 }
236
237 #[allow(unreachable_pub)]
238 pub fn was_set(&self) -> ConfigWasSet<'_> {
239 ConfigWasSet(self)
240 }
241
242 #[allow(unreachable_pub)]
243 pub fn was_set_cli(&self) -> CliConfigWasSet<'_> {
244 CliConfigWasSet(self)
245 }
246
247 fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config {
248 $(
249 if let Some(option_value) = parsed.$i {
250 let option_stable = self.$i.3;
251 if $crate::config::config_type::is_stable_option_and_value(
252 stringify!($i), option_stable, &option_value
253 ) {
254 self.$i.1 = true;
255 self.$i.2 = option_value;
256 }
257 }
258 )+
259 self.set_heuristics();
260 self.set_ignore(dir);
261 self.set_merge_imports();
262 self.set_fn_args_layout();
263 self.set_hide_parse_errors();
264 self.set_version();
265 self
266 }
267
268 #[cfg(test)]
270 pub(crate) fn hash_set() -> HashSet<String> {
271 let mut hash_set = HashSet::new();
272 $(
273 hash_set.insert(stringify!($i).to_owned());
274 )+
275 hash_set
276 }
277
278 pub(crate) fn is_valid_name(name: &str) -> bool {
279 match name {
280 $(
281 stringify!($i) => true,
282 )+
283 _ => false,
284 }
285 }
286
287 #[allow(unreachable_pub)]
288 pub fn is_valid_key_val(key: &str, val: &str) -> bool {
289 match key {
290 $(
291 stringify!($i) => {
292 val.parse::<<$ty as StyleEditionDefault>::ConfigType>().is_ok()
293 }
294 )+
295 _ => false,
296 }
297 }
298
299 #[allow(unreachable_pub)]
300 pub fn used_options(&self) -> PartialConfig {
301 PartialConfig {
302 $(
303 $i: if self.$i.0.get() {
304 Some(self.$i.2.clone())
305 } else {
306 None
307 },
308 )+
309 }
310 }
311
312 #[allow(unreachable_pub)]
313 pub fn all_options(&self) -> PartialConfig {
314 PartialConfig {
315 $(
316 $i: Some(self.$i.2.clone()),
317 )+
318 }
319 }
320
321 #[allow(unreachable_pub)]
322 pub fn override_value(&mut self, key: &str, val: &str)
323 {
324 match key {
325 $(
326 stringify!($i) => {
327 let value = val.parse::<<$ty as StyleEditionDefault>::ConfigType>()
328 .expect(
329 &format!(
330 "Failed to parse override for {} (\"{}\") as a {}",
331 stringify!($i),
332 val,
333 stringify!(<$ty as StyleEditionDefault>::ConfigType)
334 )
335 );
336
337 self.$i.1 = true;
346 self.$i.2 = value;
347 }
348 )+
349 _ => panic!("Unknown config key in override: {}", key)
350 }
351
352 match key {
353 "max_width"
354 | "use_small_heuristics"
355 | "fn_call_width"
356 | "single_line_if_else_max_width"
357 | "single_line_let_else_max_width"
358 | "attr_fn_like_width"
359 | "struct_lit_width"
360 | "struct_variant_width"
361 | "array_width"
362 | "chain_width" => self.set_heuristics(),
363 "merge_imports" => self.set_merge_imports(),
364 "fn_args_layout" => self.set_fn_args_layout(),
365 "hide_parse_errors" => self.set_hide_parse_errors(),
366 "version" => self.set_version(),
367 &_ => (),
368 }
369 }
370
371 #[allow(unreachable_pub)]
372 pub fn is_hidden_option(name: &str) -> bool {
373 const HIDE_OPTIONS: [&str; 7] = [
374 "verbose",
375 "verbose_diff",
376 "file_lines",
377 "width_heuristics",
378 "merge_imports",
379 "fn_args_layout",
380 "hide_parse_errors"
381 ];
382 HIDE_OPTIONS.contains(&name)
383 }
384
385 #[allow(unreachable_pub)]
386 pub fn print_docs(out: &mut dyn Write, include_unstable: bool) {
387 let style_edition = StyleEdition::Edition2015;
388 use std::cmp;
389 let max = 0;
390 $( let max = cmp::max(max, stringify!($i).len()+1); )+
391 let space_str = " ".repeat(max);
392 writeln!(out, "Configuration Options:").unwrap();
393 $(
394 if $stb || include_unstable {
395 let name_raw = stringify!($i);
396
397 if !Config::is_hidden_option(name_raw) {
398 let mut name_out = String::with_capacity(max);
399 for _ in name_raw.len()..max-1 {
400 name_out.push(' ')
401 }
402 name_out.push_str(name_raw);
403 name_out.push(' ');
404 let default_value = <$ty as StyleEditionDefault>::style_edition_default(
405 style_edition
406 );
407 let mut default_str = format!("{}", default_value);
408 if default_str.is_empty() {
409 default_str = String::from("\"\"");
410 }
411 writeln!(out,
412 "{}{} Default: {}{}",
413 name_out,
414 <<$ty as StyleEditionDefault>::ConfigType>::doc_hint(),
415 default_str,
416 if !$stb { " (unstable)" } else { "" }).unwrap();
417 $(
418 writeln!(out, "{}{}", space_str, $dstring).unwrap();
419 )+
420 writeln!(out).unwrap();
421 }
422 }
423 )+
424 }
425
426 #[allow(unreachable_pub)]
437 pub fn reduce_max_width(&mut self, delta: usize) {
438 self.adjust_max_width(-(delta as isize));
439 }
440
441 #[allow(unreachable_pub)]
452 pub fn increase_max_width(&mut self, delta: usize) {
453 self.adjust_max_width(delta as isize);
454 }
455
456 fn adjust_max_width(&mut self, delta: isize) {
467 let adjust = |value: usize| (value as isize + delta) as usize;
468
469 self.array_width.2 = adjust(self.array_width.2);
470 self.attr_fn_like_width.2 = adjust(self.attr_fn_like_width.2);
471 self.chain_width.2 = adjust(self.chain_width.2);
472 self.fn_call_width.2 = adjust(self.fn_call_width.2);
473 self.single_line_if_else_max_width.2 = adjust(self.single_line_if_else_max_width.2);
474 self.single_line_let_else_max_width.2 =
475 adjust(self.single_line_let_else_max_width.2);
476 self.struct_lit_width.2 = adjust(self.struct_lit_width.2);
477 self.struct_variant_width.2 = adjust(self.struct_variant_width.2);
478
479 self.max_width.2 = adjust(self.max_width.2);
480 self.set_heuristics();
481 }
482
483 fn set_width_heuristics(&mut self, heuristics: WidthHeuristics) {
484 let max_width = self.max_width.2;
485 let get_width_value = |
486 was_set: bool,
487 override_value: usize,
488 heuristic_value: usize,
489 config_key: &str,
490 | -> usize {
491 if !was_set {
492 return heuristic_value;
493 }
494 if override_value > max_width {
495 eprintln!(
496 "`{0}` cannot have a value that exceeds `max_width`. \
497 `{0}` will be set to the same value as `max_width`",
498 config_key,
499 );
500 return max_width;
501 }
502 override_value
503 };
504
505 let fn_call_width = get_width_value(
506 self.was_set().fn_call_width(),
507 self.fn_call_width.2,
508 heuristics.fn_call_width,
509 "fn_call_width",
510 );
511 self.fn_call_width.2 = fn_call_width;
512
513 let attr_fn_like_width = get_width_value(
514 self.was_set().attr_fn_like_width(),
515 self.attr_fn_like_width.2,
516 heuristics.attr_fn_like_width,
517 "attr_fn_like_width",
518 );
519 self.attr_fn_like_width.2 = attr_fn_like_width;
520
521 let struct_lit_width = get_width_value(
522 self.was_set().struct_lit_width(),
523 self.struct_lit_width.2,
524 heuristics.struct_lit_width,
525 "struct_lit_width",
526 );
527 self.struct_lit_width.2 = struct_lit_width;
528
529 let struct_variant_width = get_width_value(
530 self.was_set().struct_variant_width(),
531 self.struct_variant_width.2,
532 heuristics.struct_variant_width,
533 "struct_variant_width",
534 );
535 self.struct_variant_width.2 = struct_variant_width;
536
537 let array_width = get_width_value(
538 self.was_set().array_width(),
539 self.array_width.2,
540 heuristics.array_width,
541 "array_width",
542 );
543 self.array_width.2 = array_width;
544
545 let chain_width = get_width_value(
546 self.was_set().chain_width(),
547 self.chain_width.2,
548 heuristics.chain_width,
549 "chain_width",
550 );
551 self.chain_width.2 = chain_width;
552
553 let single_line_if_else_max_width = get_width_value(
554 self.was_set().single_line_if_else_max_width(),
555 self.single_line_if_else_max_width.2,
556 heuristics.single_line_if_else_max_width,
557 "single_line_if_else_max_width",
558 );
559 self.single_line_if_else_max_width.2 = single_line_if_else_max_width;
560
561 let single_line_let_else_max_width = get_width_value(
562 self.was_set().single_line_let_else_max_width(),
563 self.single_line_let_else_max_width.2,
564 heuristics.single_line_let_else_max_width,
565 "single_line_let_else_max_width",
566 );
567 self.single_line_let_else_max_width.2 = single_line_let_else_max_width;
568 }
569
570 fn set_heuristics(&mut self) {
571 let max_width = self.max_width.2;
572 match self.use_small_heuristics.2 {
573 Heuristics::Default =>
574 self.set_width_heuristics(WidthHeuristics::scaled(max_width)),
575 Heuristics::Max => self.set_width_heuristics(WidthHeuristics::set(max_width)),
576 Heuristics::Off => self.set_width_heuristics(WidthHeuristics::null()),
577 };
578 }
579
580 fn set_ignore(&mut self, dir: &Path) {
581 self.ignore.2.add_prefix(dir);
582 }
583
584 fn set_merge_imports(&mut self) {
585 if self.was_set().merge_imports() {
586 eprintln!(
587 "Warning: the `merge_imports` option is deprecated. \
588 Use `imports_granularity=\"Crate\"` instead"
589 );
590 if !self.was_set().imports_granularity() {
591 self.imports_granularity.2 = if self.merge_imports() {
592 ImportGranularity::Crate
593 } else {
594 ImportGranularity::Preserve
595 };
596 }
597 }
598 }
599
600 fn set_fn_args_layout(&mut self) {
601 if self.was_set().fn_args_layout() {
602 eprintln!(
603 "Warning: the `fn_args_layout` option is deprecated. \
604 Use `fn_params_layout`. instead"
605 );
606 if !self.was_set().fn_params_layout() {
607 self.fn_params_layout.2 = self.fn_args_layout();
608 }
609 }
610 }
611
612 fn set_hide_parse_errors(&mut self) {
613 if self.was_set().hide_parse_errors() {
614 eprintln!(
615 "Warning: the `hide_parse_errors` option is deprecated. \
616 Use `show_parse_errors` instead"
617 );
618 if !self.was_set().show_parse_errors() {
619 self.show_parse_errors.2 = self.hide_parse_errors();
620 }
621 }
622 }
623
624 fn set_version(&mut self) {
625 if !self.was_set().version() {
626 return;
627 }
628
629 eprintln!(
630 "Warning: the `version` option is deprecated. \
631 Use `style_edition=\"{0}\"` instead.",
632 match self.version.2 {
633 Version::One => "2015",
634 Version::Two => "2024",
635 }
636 );
637
638 if self.was_set().style_edition() || self.was_set_cli().style_edition() {
639 eprintln!(
640 "Warning: the deprecated `version` option was \
641 used in conjunction with the `style_edition` \
642 option which takes precedence. \
643 The value of the `version` option will be ignored."
644 );
645 }
646 }
647
648 #[allow(unreachable_pub)]
649 pub fn is_default(&self, key: &str) -> bool {
651 let style_edition = StyleEdition::Edition2015;
652 $(
653 let default_value = <$ty as StyleEditionDefault>::style_edition_default(
654 style_edition
655 );
656 if let stringify!($i) = key {
657 return self.$i.1 && self.$i.2 == default_value;
658 }
659 )+
660 false
661 }
662 }
663
664 impl Default for Config {
666 fn default() -> Config {
667 Config::default_with_style_edition(StyleEdition::Edition2015)
668 }
669 }
670 )
671}
672
673pub(crate) fn is_stable_option_and_value<T>(
674 option_name: &str,
675 option_stable: bool,
676 option_value: &T,
677) -> bool
678where
679 T: PartialEq + std::fmt::Debug + ConfigType,
680{
681 let nightly = crate::is_nightly_channel!();
682 let variant_stable = option_value.stable_variant();
683 match (nightly, option_stable, variant_stable) {
684 (false, false, _) => {
686 eprintln!(
687 "Warning: can't set `{option_name} = {option_value:?}`, unstable features are only \
688 available in nightly channel."
689 );
690 false
691 }
692 (false, true, false) => {
694 eprintln!(
695 "Warning: can't set `{option_name} = {option_value:?}`, unstable variants are only \
696 available in nightly channel."
697 );
698 false
699 }
700 (true, _, _) | (false, true, true) => true,
703 }
704}