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 fn set_width_heuristics(&mut self, heuristics: WidthHeuristics) {
427 let max_width = self.max_width.2;
428 let get_width_value = |
429 was_set: bool,
430 override_value: usize,
431 heuristic_value: usize,
432 config_key: &str,
433 | -> usize {
434 if !was_set {
435 return heuristic_value;
436 }
437 if override_value > max_width {
438 eprintln!(
439 "`{0}` cannot have a value that exceeds `max_width`. \
440 `{0}` will be set to the same value as `max_width`",
441 config_key,
442 );
443 return max_width;
444 }
445 override_value
446 };
447
448 let fn_call_width = get_width_value(
449 self.was_set().fn_call_width(),
450 self.fn_call_width.2,
451 heuristics.fn_call_width,
452 "fn_call_width",
453 );
454 self.fn_call_width.2 = fn_call_width;
455
456 let attr_fn_like_width = get_width_value(
457 self.was_set().attr_fn_like_width(),
458 self.attr_fn_like_width.2,
459 heuristics.attr_fn_like_width,
460 "attr_fn_like_width",
461 );
462 self.attr_fn_like_width.2 = attr_fn_like_width;
463
464 let struct_lit_width = get_width_value(
465 self.was_set().struct_lit_width(),
466 self.struct_lit_width.2,
467 heuristics.struct_lit_width,
468 "struct_lit_width",
469 );
470 self.struct_lit_width.2 = struct_lit_width;
471
472 let struct_variant_width = get_width_value(
473 self.was_set().struct_variant_width(),
474 self.struct_variant_width.2,
475 heuristics.struct_variant_width,
476 "struct_variant_width",
477 );
478 self.struct_variant_width.2 = struct_variant_width;
479
480 let array_width = get_width_value(
481 self.was_set().array_width(),
482 self.array_width.2,
483 heuristics.array_width,
484 "array_width",
485 );
486 self.array_width.2 = array_width;
487
488 let chain_width = get_width_value(
489 self.was_set().chain_width(),
490 self.chain_width.2,
491 heuristics.chain_width,
492 "chain_width",
493 );
494 self.chain_width.2 = chain_width;
495
496 let single_line_if_else_max_width = get_width_value(
497 self.was_set().single_line_if_else_max_width(),
498 self.single_line_if_else_max_width.2,
499 heuristics.single_line_if_else_max_width,
500 "single_line_if_else_max_width",
501 );
502 self.single_line_if_else_max_width.2 = single_line_if_else_max_width;
503
504 let single_line_let_else_max_width = get_width_value(
505 self.was_set().single_line_let_else_max_width(),
506 self.single_line_let_else_max_width.2,
507 heuristics.single_line_let_else_max_width,
508 "single_line_let_else_max_width",
509 );
510 self.single_line_let_else_max_width.2 = single_line_let_else_max_width;
511 }
512
513 fn set_heuristics(&mut self) {
514 let max_width = self.max_width.2;
515 match self.use_small_heuristics.2 {
516 Heuristics::Default =>
517 self.set_width_heuristics(WidthHeuristics::scaled(max_width)),
518 Heuristics::Max => self.set_width_heuristics(WidthHeuristics::set(max_width)),
519 Heuristics::Off => self.set_width_heuristics(WidthHeuristics::null()),
520 };
521 }
522
523 fn set_ignore(&mut self, dir: &Path) {
524 self.ignore.2.add_prefix(dir);
525 }
526
527 fn set_merge_imports(&mut self) {
528 if self.was_set().merge_imports() {
529 eprintln!(
530 "Warning: the `merge_imports` option is deprecated. \
531 Use `imports_granularity=\"Crate\"` instead"
532 );
533 if !self.was_set().imports_granularity() {
534 self.imports_granularity.2 = if self.merge_imports() {
535 ImportGranularity::Crate
536 } else {
537 ImportGranularity::Preserve
538 };
539 }
540 }
541 }
542
543 fn set_fn_args_layout(&mut self) {
544 if self.was_set().fn_args_layout() {
545 eprintln!(
546 "Warning: the `fn_args_layout` option is deprecated. \
547 Use `fn_params_layout`. instead"
548 );
549 if !self.was_set().fn_params_layout() {
550 self.fn_params_layout.2 = self.fn_args_layout();
551 }
552 }
553 }
554
555 fn set_hide_parse_errors(&mut self) {
556 if self.was_set().hide_parse_errors() {
557 eprintln!(
558 "Warning: the `hide_parse_errors` option is deprecated. \
559 Use `show_parse_errors` instead"
560 );
561 if !self.was_set().show_parse_errors() {
562 self.show_parse_errors.2 = self.hide_parse_errors();
563 }
564 }
565 }
566
567 fn set_version(&mut self) {
568 if !self.was_set().version() {
569 return;
570 }
571
572 eprintln!(
573 "Warning: the `version` option is deprecated. \
574 Use `style_edition` instead."
575 );
576
577 if self.was_set().style_edition() || self.was_set_cli().style_edition() {
578 eprintln!(
579 "Warning: the deprecated `version` option was \
580 used in conjunction with the `style_edition` \
581 option which takes precedence. \
582 The value of the `version` option will be ignored."
583 );
584 }
585 }
586
587 #[allow(unreachable_pub)]
588 pub fn is_default(&self, key: &str) -> bool {
590 let style_edition = StyleEdition::Edition2015;
591 $(
592 let default_value = <$ty as StyleEditionDefault>::style_edition_default(
593 style_edition
594 );
595 if let stringify!($i) = key {
596 return self.$i.1 && self.$i.2 == default_value;
597 }
598 )+
599 false
600 }
601 }
602
603 impl Default for Config {
605 fn default() -> Config {
606 Config::default_with_style_edition(StyleEdition::Edition2015)
607 }
608 }
609 )
610}
611
612pub(crate) fn is_stable_option_and_value<T>(
613 option_name: &str,
614 option_stable: bool,
615 option_value: &T,
616) -> bool
617where
618 T: PartialEq + std::fmt::Debug + ConfigType,
619{
620 let nightly = crate::is_nightly_channel!();
621 let variant_stable = option_value.stable_variant();
622 match (nightly, option_stable, variant_stable) {
623 (false, false, _) => {
625 eprintln!(
626 "Warning: can't set `{option_name} = {option_value:?}`, unstable features are only \
627 available in nightly channel."
628 );
629 false
630 }
631 (false, true, false) => {
633 eprintln!(
634 "Warning: can't set `{option_name} = {option_value:?}`, unstable variants are only \
635 available in nightly channel."
636 );
637 false
638 }
639 (true, _, _) | (false, true, true) => true,
642 }
643}