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.min(isize::MAX as usize) as isize));
439 }
440
441 #[allow(unreachable_pub)]
452 pub fn increase_max_width(&mut self, delta: usize) {
453 self.adjust_max_width(delta.min(isize::MAX as usize) as isize);
454 }
455
456 fn adjust_max_width(&mut self, delta: isize) {
467 let adjust = |value: usize| value.saturating_add_signed(delta);
470
471 self.array_width.2 = adjust(self.array_width.2);
472 self.attr_fn_like_width.2 = adjust(self.attr_fn_like_width.2);
473 self.chain_width.2 = adjust(self.chain_width.2);
474 self.fn_call_width.2 = adjust(self.fn_call_width.2);
475 self.single_line_if_else_max_width.2 = adjust(self.single_line_if_else_max_width.2);
476 self.single_line_let_else_max_width.2 =
477 adjust(self.single_line_let_else_max_width.2);
478 self.struct_lit_width.2 = adjust(self.struct_lit_width.2);
479 self.struct_variant_width.2 = adjust(self.struct_variant_width.2);
480
481 self.max_width.2 = adjust(self.max_width.2);
482 self.set_heuristics();
483 }
484
485 fn set_width_heuristics(&mut self, heuristics: WidthHeuristics) {
486 let max_width = self.max_width.2;
487 let get_width_value = |
488 was_set: bool,
489 override_value: usize,
490 heuristic_value: usize,
491 config_key: &str,
492 | -> usize {
493 if !was_set {
494 return heuristic_value;
495 }
496 if override_value > max_width {
497 eprintln!(
498 "`{0}` cannot have a value that exceeds `max_width`. \
499 `{0}` will be set to the same value as `max_width`",
500 config_key,
501 );
502 return max_width;
503 }
504 override_value
505 };
506
507 let fn_call_width = get_width_value(
508 self.was_set().fn_call_width(),
509 self.fn_call_width.2,
510 heuristics.fn_call_width,
511 "fn_call_width",
512 );
513 self.fn_call_width.2 = fn_call_width;
514
515 let attr_fn_like_width = get_width_value(
516 self.was_set().attr_fn_like_width(),
517 self.attr_fn_like_width.2,
518 heuristics.attr_fn_like_width,
519 "attr_fn_like_width",
520 );
521 self.attr_fn_like_width.2 = attr_fn_like_width;
522
523 let struct_lit_width = get_width_value(
524 self.was_set().struct_lit_width(),
525 self.struct_lit_width.2,
526 heuristics.struct_lit_width,
527 "struct_lit_width",
528 );
529 self.struct_lit_width.2 = struct_lit_width;
530
531 let struct_variant_width = get_width_value(
532 self.was_set().struct_variant_width(),
533 self.struct_variant_width.2,
534 heuristics.struct_variant_width,
535 "struct_variant_width",
536 );
537 self.struct_variant_width.2 = struct_variant_width;
538
539 let array_width = get_width_value(
540 self.was_set().array_width(),
541 self.array_width.2,
542 heuristics.array_width,
543 "array_width",
544 );
545 self.array_width.2 = array_width;
546
547 let chain_width = get_width_value(
548 self.was_set().chain_width(),
549 self.chain_width.2,
550 heuristics.chain_width,
551 "chain_width",
552 );
553 self.chain_width.2 = chain_width;
554
555 let single_line_if_else_max_width = get_width_value(
556 self.was_set().single_line_if_else_max_width(),
557 self.single_line_if_else_max_width.2,
558 heuristics.single_line_if_else_max_width,
559 "single_line_if_else_max_width",
560 );
561 self.single_line_if_else_max_width.2 = single_line_if_else_max_width;
562
563 let single_line_let_else_max_width = get_width_value(
564 self.was_set().single_line_let_else_max_width(),
565 self.single_line_let_else_max_width.2,
566 heuristics.single_line_let_else_max_width,
567 "single_line_let_else_max_width",
568 );
569 self.single_line_let_else_max_width.2 = single_line_let_else_max_width;
570 }
571
572 fn set_heuristics(&mut self) {
573 let max_width = self.max_width.2;
574 match self.use_small_heuristics.2 {
575 Heuristics::Default =>
576 self.set_width_heuristics(WidthHeuristics::scaled(max_width)),
577 Heuristics::Max => self.set_width_heuristics(WidthHeuristics::set(max_width)),
578 Heuristics::Off => self.set_width_heuristics(WidthHeuristics::null()),
579 };
580 }
581
582 fn set_ignore(&mut self, dir: &Path) {
583 self.ignore.2.add_prefix(dir);
584 }
585
586 fn set_merge_imports(&mut self) {
587 if self.was_set().merge_imports() {
588 eprintln!(
589 "Warning: the `merge_imports` option is deprecated. \
590 Use `imports_granularity=\"Crate\"` instead"
591 );
592 if !self.was_set().imports_granularity() {
593 self.imports_granularity.2 = if self.merge_imports() {
594 ImportGranularity::Crate
595 } else {
596 ImportGranularity::Preserve
597 };
598 }
599 }
600 }
601
602 fn set_fn_args_layout(&mut self) {
603 if self.was_set().fn_args_layout() {
604 eprintln!(
605 "Warning: the `fn_args_layout` option is deprecated. \
606 Use `fn_params_layout`. instead"
607 );
608 if !self.was_set().fn_params_layout() {
609 self.fn_params_layout.2 = self.fn_args_layout();
610 }
611 }
612 }
613
614 fn set_hide_parse_errors(&mut self) {
615 if self.was_set().hide_parse_errors() {
616 eprintln!(
617 "Warning: the `hide_parse_errors` option is deprecated. \
618 Use `show_parse_errors` instead"
619 );
620 if !self.was_set().show_parse_errors() {
621 self.show_parse_errors.2 = self.hide_parse_errors();
622 }
623 }
624 }
625
626 fn set_version(&mut self) {
627 if !self.was_set().version() {
628 return;
629 }
630
631 eprintln!(
632 "Warning: the `version` option is deprecated. \
633 Use `style_edition=\"{0}\"` instead.",
634 match self.version.2 {
635 Version::One => "2015",
636 Version::Two => "2024",
637 }
638 );
639
640 if self.was_set().style_edition() || self.was_set_cli().style_edition() {
641 eprintln!(
642 "Warning: the deprecated `version` option was \
643 used in conjunction with the `style_edition` \
644 option which takes precedence. \
645 The value of the `version` option will be ignored."
646 );
647 }
648 }
649
650 #[allow(unreachable_pub)]
651 pub fn is_default(&self, key: &str) -> bool {
653 let style_edition = StyleEdition::Edition2015;
654 $(
655 let default_value = <$ty as StyleEditionDefault>::style_edition_default(
656 style_edition
657 );
658 if let stringify!($i) = key {
659 return self.$i.1 && self.$i.2 == default_value;
660 }
661 )+
662 false
663 }
664 }
665
666 impl Default for Config {
668 fn default() -> Config {
669 Config::default_with_style_edition(StyleEdition::Edition2015)
670 }
671 }
672 )
673}
674
675pub(crate) fn is_stable_option_and_value<T>(
676 option_name: &str,
677 option_stable: bool,
678 option_value: &T,
679) -> bool
680where
681 T: PartialEq + std::fmt::Debug + ConfigType,
682{
683 let nightly = crate::is_nightly_channel!();
684 let variant_stable = option_value.stable_variant();
685 match (nightly, option_stable, variant_stable) {
686 (false, false, _) => {
688 eprintln!(
689 "Warning: can't set `{option_name} = {option_value:?}`, unstable features are only \
690 available in nightly channel."
691 );
692 false
693 }
694 (false, true, false) => {
696 eprintln!(
697 "Warning: can't set `{option_name} = {option_value:?}`, unstable variants are only \
698 available in nightly channel."
699 );
700 false
701 }
702 (true, _, _) | (false, true, true) => true,
705 }
706}