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