133d722a9Sopenharmony_ciuse crate::gen::{CfgEvaluator, CfgResult};
233d722a9Sopenharmony_ciuse std::collections::{BTreeMap as Map, BTreeSet as Set};
333d722a9Sopenharmony_ciuse std::fmt::{self, Debug};
433d722a9Sopenharmony_ciuse syn::parse::ParseStream;
533d722a9Sopenharmony_ciuse syn::{Ident, LitBool, LitStr, Token};
633d722a9Sopenharmony_ci
733d722a9Sopenharmony_ci#[derive(Ord, PartialOrd, Eq, PartialEq)]
833d722a9Sopenharmony_cipub enum CfgValue {
933d722a9Sopenharmony_ci    Bool(bool),
1033d722a9Sopenharmony_ci    Str(String),
1133d722a9Sopenharmony_ci}
1233d722a9Sopenharmony_ci
1333d722a9Sopenharmony_ciimpl CfgValue {
1433d722a9Sopenharmony_ci    const FALSE: Self = CfgValue::Bool(false);
1533d722a9Sopenharmony_ci    const TRUE: Self = CfgValue::Bool(true);
1633d722a9Sopenharmony_ci}
1733d722a9Sopenharmony_ci
1833d722a9Sopenharmony_cipub struct FlagsCfgEvaluator {
1933d722a9Sopenharmony_ci    map: Map<String, Set<CfgValue>>,
2033d722a9Sopenharmony_ci}
2133d722a9Sopenharmony_ci
2233d722a9Sopenharmony_ciimpl FlagsCfgEvaluator {
2333d722a9Sopenharmony_ci    pub fn new(map: Map<String, Set<CfgValue>>) -> Self {
2433d722a9Sopenharmony_ci        FlagsCfgEvaluator { map }
2533d722a9Sopenharmony_ci    }
2633d722a9Sopenharmony_ci}
2733d722a9Sopenharmony_ci
2833d722a9Sopenharmony_ciimpl CfgEvaluator for FlagsCfgEvaluator {
2933d722a9Sopenharmony_ci    fn eval(&self, name: &str, value: Option<&str>) -> CfgResult {
3033d722a9Sopenharmony_ci        let set = self.map.get(name);
3133d722a9Sopenharmony_ci        if let Some(value) = value {
3233d722a9Sopenharmony_ci            if let Some(set) = set {
3333d722a9Sopenharmony_ci                CfgResult::from(set.contains(&CfgValue::Str(value.to_owned())))
3433d722a9Sopenharmony_ci            } else if name == "feature" {
3533d722a9Sopenharmony_ci                CfgResult::False
3633d722a9Sopenharmony_ci            } else {
3733d722a9Sopenharmony_ci                let msg = format!(
3833d722a9Sopenharmony_ci                    "pass `--cfg {}=\"...\"` to be able to use this attribute",
3933d722a9Sopenharmony_ci                    name,
4033d722a9Sopenharmony_ci                );
4133d722a9Sopenharmony_ci                CfgResult::Undetermined { msg }
4233d722a9Sopenharmony_ci            }
4333d722a9Sopenharmony_ci        } else {
4433d722a9Sopenharmony_ci            let (mut is_false, mut is_true) = (false, false);
4533d722a9Sopenharmony_ci            if let Some(set) = set {
4633d722a9Sopenharmony_ci                is_false = set.contains(&CfgValue::FALSE);
4733d722a9Sopenharmony_ci                is_true = set.contains(&CfgValue::TRUE);
4833d722a9Sopenharmony_ci            }
4933d722a9Sopenharmony_ci            if is_false && is_true {
5033d722a9Sopenharmony_ci                let msg = format!("the cxxbridge flags say both {0}=false and {0}=true", name);
5133d722a9Sopenharmony_ci                CfgResult::Undetermined { msg }
5233d722a9Sopenharmony_ci            } else if is_false {
5333d722a9Sopenharmony_ci                CfgResult::False
5433d722a9Sopenharmony_ci            } else if is_true {
5533d722a9Sopenharmony_ci                CfgResult::True
5633d722a9Sopenharmony_ci            } else {
5733d722a9Sopenharmony_ci                let msg = format!(
5833d722a9Sopenharmony_ci                    "pass either `--cfg {0}=true` or `--cfg {0}=false` to be able to use this cfg attribute",
5933d722a9Sopenharmony_ci                    name,
6033d722a9Sopenharmony_ci                );
6133d722a9Sopenharmony_ci                CfgResult::Undetermined { msg }
6233d722a9Sopenharmony_ci            }
6333d722a9Sopenharmony_ci        }
6433d722a9Sopenharmony_ci    }
6533d722a9Sopenharmony_ci}
6633d722a9Sopenharmony_ci
6733d722a9Sopenharmony_ciimpl Debug for CfgValue {
6833d722a9Sopenharmony_ci    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
6933d722a9Sopenharmony_ci        match self {
7033d722a9Sopenharmony_ci            CfgValue::Bool(value) => Debug::fmt(value, formatter),
7133d722a9Sopenharmony_ci            CfgValue::Str(value) => Debug::fmt(value, formatter),
7233d722a9Sopenharmony_ci        }
7333d722a9Sopenharmony_ci    }
7433d722a9Sopenharmony_ci}
7533d722a9Sopenharmony_ci
7633d722a9Sopenharmony_cipub fn parse(input: ParseStream) -> syn::Result<(String, CfgValue)> {
7733d722a9Sopenharmony_ci    let ident: Ident = input.parse()?;
7833d722a9Sopenharmony_ci    let name = ident.to_string();
7933d722a9Sopenharmony_ci    if input.is_empty() {
8033d722a9Sopenharmony_ci        return Ok((name, CfgValue::TRUE));
8133d722a9Sopenharmony_ci    }
8233d722a9Sopenharmony_ci    input.parse::<Token![=]>()?;
8333d722a9Sopenharmony_ci    let lookahead = input.lookahead1();
8433d722a9Sopenharmony_ci    if lookahead.peek(LitBool) {
8533d722a9Sopenharmony_ci        let lit: LitBool = input.parse()?;
8633d722a9Sopenharmony_ci        Ok((name, CfgValue::Bool(lit.value)))
8733d722a9Sopenharmony_ci    } else if lookahead.peek(LitStr) {
8833d722a9Sopenharmony_ci        let lit: LitStr = input.parse()?;
8933d722a9Sopenharmony_ci        Ok((name, CfgValue::Str(lit.value())))
9033d722a9Sopenharmony_ci    } else {
9133d722a9Sopenharmony_ci        Err(lookahead.error())
9233d722a9Sopenharmony_ci    }
9333d722a9Sopenharmony_ci}
94