1use std::fmt;
2
3use rustc_macros::{Decodable, Encodable, HashStable_Generic};
4use rustc_span::{Span, Symbol};
5use thin_vec::ThinVec;
6
7use crate::attr::version::RustcVersion;
8
9#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
10pub enum CfgEntry {
11 All(ThinVec<CfgEntry>, Span),
12 Any(ThinVec<CfgEntry>, Span),
13 Not(Box<CfgEntry>, Span),
14 Bool(bool, Span),
15 NameValue { name: Symbol, value: Option<Symbol>, span: Span },
16 Version(Option<RustcVersion>, Span),
17}
18
19impl CfgEntry {
20 pub fn lower_spans(&mut self, lower_span: impl Copy + Fn(Span) -> Span) {
21 match self {
22 CfgEntry::All(subs, span) | CfgEntry::Any(subs, span) => {
23 *span = lower_span(*span);
24 subs.iter_mut().for_each(|sub| sub.lower_spans(lower_span));
25 }
26 CfgEntry::Not(sub, span) => {
27 *span = lower_span(*span);
28 sub.lower_spans(lower_span);
29 }
30 CfgEntry::Bool(_, span)
31 | CfgEntry::NameValue { span, .. }
32 | CfgEntry::Version(_, span) => {
33 *span = lower_span(*span);
34 }
35 }
36 }
37
38 pub fn span(&self) -> Span {
39 let (Self::All(_, span)
40 | Self::Any(_, span)
41 | Self::Not(_, span)
42 | Self::Bool(_, span)
43 | Self::NameValue { span, .. }
44 | Self::Version(_, span)) = self;
45 *span
46 }
47
48 pub fn is_equivalent_to(&self, other: &Self) -> bool {
50 match (self, other) {
51 (Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => {
52 a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b)))
53 }
54 (Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b),
55 (Self::Bool(a, _), Self::Bool(b, _)) => a == b,
56 (
57 Self::NameValue { name: name1, value: value1, .. },
58 Self::NameValue { name: name2, value: value2, .. },
59 ) => name1 == name2 && value1 == value2,
60 (Self::Version(a, _), Self::Version(b, _)) => a == b,
61 _ => false,
62 }
63 }
64}
65
66impl fmt::Display for CfgEntry {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 fn write_entries(
69 name: &str,
70 entries: &[CfgEntry],
71 f: &mut fmt::Formatter<'_>,
72 ) -> fmt::Result {
73 write!(f, "{name}(")?;
74 for (nb, entry) in entries.iter().enumerate() {
75 if nb != 0 {
76 f.write_str(", ")?;
77 }
78 entry.fmt(f)?;
79 }
80 f.write_str(")")
81 }
82 match self {
83 Self::All(entries, _) => write_entries("all", entries, f),
84 Self::Any(entries, _) => write_entries("any", entries, f),
85 Self::Not(entry, _) => write!(f, "not({entry})"),
86 Self::Bool(value, _) => write!(f, "{value}"),
87 Self::NameValue { name, value, .. } => {
88 match value {
89 Some(value) => write!(f, "{name} = {:?}", value.as_str()),
92 None => write!(f, "{name}"),
93 }
94 }
95 Self::Version(version, _) => match version {
96 Some(version) => write!(f, "{version}"),
97 None => Ok(()),
98 },
99 }
100 }
101}