• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::gen::{CfgEvaluator, CfgResult};
2 use std::collections::{BTreeMap as Map, BTreeSet as Set};
3 use std::fmt::{self, Debug};
4 use syn::parse::ParseStream;
5 use syn::{Ident, LitBool, LitStr, Token};
6 
7 #[derive(Ord, PartialOrd, Eq, PartialEq)]
8 pub enum CfgValue {
9     Bool(bool),
10     Str(String),
11 }
12 
13 impl CfgValue {
14     const FALSE: Self = CfgValue::Bool(false);
15     const TRUE: Self = CfgValue::Bool(true);
16 }
17 
18 pub struct FlagsCfgEvaluator {
19     map: Map<String, Set<CfgValue>>,
20 }
21 
22 impl FlagsCfgEvaluator {
new(map: Map<String, Set<CfgValue>>) -> Self23     pub fn new(map: Map<String, Set<CfgValue>>) -> Self {
24         FlagsCfgEvaluator { map }
25     }
26 }
27 
28 impl CfgEvaluator for FlagsCfgEvaluator {
eval(&self, name: &str, value: Option<&str>) -> CfgResult29     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 
67 impl Debug for CfgValue {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result68     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 
parse(input: ParseStream) -> syn::Result<(String, CfgValue)>76 pub 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