xref: /third_party/rust/crates/cxx/gen/cmd/src/cfg.rs (revision 33d722a9)
1use crate::gen::{CfgEvaluator, CfgResult};
2use std::collections::{BTreeMap as Map, BTreeSet as Set};
3use std::fmt::{self, Debug};
4use syn::parse::ParseStream;
5use syn::{Ident, LitBool, LitStr, Token};
6
7#[derive(Ord, PartialOrd, Eq, PartialEq)]
8pub enum CfgValue {
9    Bool(bool),
10    Str(String),
11}
12
13impl CfgValue {
14    const FALSE: Self = CfgValue::Bool(false);
15    const TRUE: Self = CfgValue::Bool(true);
16}
17
18pub struct FlagsCfgEvaluator {
19    map: Map<String, Set<CfgValue>>,
20}
21
22impl FlagsCfgEvaluator {
23    pub fn new(map: Map<String, Set<CfgValue>>) -> Self {
24        FlagsCfgEvaluator { map }
25    }
26}
27
28impl CfgEvaluator for FlagsCfgEvaluator {
29    fn eval(&self, name: &str, value: Option<&str>) -> CfgResult {
30        let set = self.map.get(name);
31        if let Some(value) = value {
32            if let Some(set) = set {
33                CfgResult::from(set.contains(&CfgValue::Str(value.to_owned())))
34            } else if name == "feature" {
35                CfgResult::False
36            } else {
37                let msg = format!(
38                    "pass `--cfg {}=\"...\"` to be able to use this attribute",
39                    name,
40                );
41                CfgResult::Undetermined { msg }
42            }
43        } else {
44            let (mut is_false, mut is_true) = (false, false);
45            if let Some(set) = set {
46                is_false = set.contains(&CfgValue::FALSE);
47                is_true = set.contains(&CfgValue::TRUE);
48            }
49            if is_false && is_true {
50                let msg = format!("the cxxbridge flags say both {0}=false and {0}=true", name);
51                CfgResult::Undetermined { msg }
52            } else if is_false {
53                CfgResult::False
54            } else if is_true {
55                CfgResult::True
56            } else {
57                let msg = format!(
58                    "pass either `--cfg {0}=true` or `--cfg {0}=false` to be able to use this cfg attribute",
59                    name,
60                );
61                CfgResult::Undetermined { msg }
62            }
63        }
64    }
65}
66
67impl Debug for CfgValue {
68    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
69        match self {
70            CfgValue::Bool(value) => Debug::fmt(value, formatter),
71            CfgValue::Str(value) => Debug::fmt(value, formatter),
72        }
73    }
74}
75
76pub fn parse(input: ParseStream) -> syn::Result<(String, CfgValue)> {
77    let ident: Ident = input.parse()?;
78    let name = ident.to_string();
79    if input.is_empty() {
80        return Ok((name, CfgValue::TRUE));
81    }
82    input.parse::<Token![=]>()?;
83    let lookahead = input.lookahead1();
84    if lookahead.peek(LitBool) {
85        let lit: LitBool = input.parse()?;
86        Ok((name, CfgValue::Bool(lit.value)))
87    } else if lookahead.peek(LitStr) {
88        let lit: LitStr = input.parse()?;
89        Ok((name, CfgValue::Str(lit.value())))
90    } else {
91        Err(lookahead.error())
92    }
93}
94