blob: 92b954cd273a2d3dd32607cf6f1953b334f25030 [file] [log] [blame]
use crate::gen::{CfgEvaluator, CfgResult};
use std::collections::{BTreeMap as Map, BTreeSet as Set};
use std::fmt::{self, Debug};
use syn::parse::ParseStream;
use syn::{Ident, LitBool, LitStr, Token};
#[derive(Ord, PartialOrd, Eq, PartialEq)]
pub(crate) enum CfgValue {
Bool(bool),
Str(String),
}
impl CfgValue {
const FALSE: Self = CfgValue::Bool(false);
const TRUE: Self = CfgValue::Bool(true);
}
pub(crate) struct FlagsCfgEvaluator {
map: Map<String, Set<CfgValue>>,
}
impl FlagsCfgEvaluator {
pub(crate) fn new(map: Map<String, Set<CfgValue>>) -> Self {
FlagsCfgEvaluator { map }
}
}
impl CfgEvaluator for FlagsCfgEvaluator {
fn eval(&self, name: &str, value: Option<&str>) -> CfgResult {
let set = self.map.get(name);
if let Some(value) = value {
if let Some(set) = set {
CfgResult::from(set.contains(&CfgValue::Str(value.to_owned())))
} else if name == "feature" {
CfgResult::False
} else {
let msg = format!(
"pass `--cfg {}=\"...\"` to be able to use this attribute",
name,
);
CfgResult::Undetermined { msg }
}
} else {
let (mut is_false, mut is_true) = (false, false);
if let Some(set) = set {
is_false = set.contains(&CfgValue::FALSE);
is_true = set.contains(&CfgValue::TRUE);
}
if is_false && is_true {
let msg = format!("the cxxbridge flags say both {0}=false and {0}=true", name);
CfgResult::Undetermined { msg }
} else if is_false {
CfgResult::False
} else if is_true {
CfgResult::True
} else {
let msg = format!(
"pass either `--cfg {0}=true` or `--cfg {0}=false` to be able to use this cfg attribute",
name,
);
CfgResult::Undetermined { msg }
}
}
}
}
impl Debug for CfgValue {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self {
CfgValue::Bool(value) => Debug::fmt(value, formatter),
CfgValue::Str(value) => Debug::fmt(value, formatter),
}
}
}
pub(crate) fn parse(input: ParseStream) -> syn::Result<(String, CfgValue)> {
let ident: Ident = input.parse()?;
let name = ident.to_string();
if input.is_empty() {
return Ok((name, CfgValue::TRUE));
}
input.parse::<Token![=]>()?;
let lookahead = input.lookahead1();
if lookahead.peek(LitBool) {
let lit: LitBool = input.parse()?;
Ok((name, CfgValue::Bool(lit.value)))
} else if lookahead.peek(LitStr) {
let lit: LitStr = input.parse()?;
Ok((name, CfgValue::Str(lit.value())))
} else {
Err(lookahead.error())
}
}