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