cxx_build/gen/
cfg.rs

1use crate::gen::{CfgEvaluator, CfgResult};
2use crate::syntax::cfg::CfgExpr;
3use crate::syntax::report::Errors;
4use crate::syntax::Api;
5use quote::quote;
6use std::collections::BTreeSet as Set;
7use std::mem;
8use syn::{Error, LitStr};
9
10pub(super) struct UnsupportedCfgEvaluator;
11
12impl CfgEvaluator for UnsupportedCfgEvaluator {
13    fn eval(&self, name: &str, value: Option<&str>) -> CfgResult {
14        let _ = name;
15        let _ = value;
16        let msg = "cfg attribute is not supported".to_owned();
17        CfgResult::Undetermined { msg }
18    }
19}
20
21pub(super) fn strip(
22    cx: &mut Errors,
23    cfg_errors: &mut Set<String>,
24    cfg_evaluator: &dyn CfgEvaluator,
25    apis: &mut Vec<Api>,
26) {
27    let mut eval = |cfg: &mut CfgExpr| {
28        let cfg = mem::replace(cfg, CfgExpr::Unconditional);
29        self::eval(cx, cfg_errors, cfg_evaluator, &cfg)
30    };
31    apis.retain_mut(|api| {
32        eval(match api {
33            Api::Include(include) => &mut include.cfg,
34            Api::Struct(strct) => &mut strct.cfg,
35            Api::Enum(enm) => &mut enm.cfg,
36            Api::CxxType(ety) | Api::RustType(ety) => &mut ety.cfg,
37            Api::CxxFunction(efn) | Api::RustFunction(efn) => &mut efn.cfg,
38            Api::TypeAlias(alias) => &mut alias.cfg,
39            Api::Impl(imp) => &mut imp.cfg,
40        })
41    });
42    for api in apis {
43        match api {
44            Api::Struct(strct) => strct.fields.retain_mut(|field| eval(&mut field.cfg)),
45            Api::Enum(enm) => enm.variants.retain_mut(|variant| eval(&mut variant.cfg)),
46            _ => {}
47        }
48    }
49}
50
51pub(super) fn eval(
52    cx: &mut Errors,
53    cfg_errors: &mut Set<String>,
54    cfg_evaluator: &dyn CfgEvaluator,
55    expr: &CfgExpr,
56) -> bool {
57    match try_eval(cfg_evaluator, expr) {
58        Ok(value) => value,
59        Err(errors) => {
60            for error in errors {
61                if cfg_errors.insert(error.to_string()) {
62                    cx.push(error);
63                }
64            }
65            false
66        }
67    }
68}
69
70fn try_eval(cfg_evaluator: &dyn CfgEvaluator, expr: &CfgExpr) -> Result<bool, Vec<Error>> {
71    match expr {
72        CfgExpr::Unconditional => Ok(true),
73        CfgExpr::Eq(ident, string) => {
74            let key = ident.to_string();
75            let value = string.as_ref().map(LitStr::value);
76            match cfg_evaluator.eval(&key, value.as_deref()) {
77                CfgResult::True => Ok(true),
78                CfgResult::False => Ok(false),
79                CfgResult::Undetermined { msg } => {
80                    let span = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::ToTokens::to_tokens(&string, &mut _s);
    _s
}quote!(#ident #string);
81                    Err(<[_]>::into_vec(::alloc::boxed::box_new([Error::new_spanned(span, msg)]))vec![Error::new_spanned(span, msg)])
82                }
83            }
84        }
85        CfgExpr::All(list) => {
86            let mut all_errors = Vec::new();
87            for subexpr in list {
88                match try_eval(cfg_evaluator, subexpr) {
89                    Ok(true) => {}
90                    Ok(false) => return Ok(false),
91                    Err(errors) => all_errors.extend(errors),
92                }
93            }
94            if all_errors.is_empty() {
95                Ok(true)
96            } else {
97                Err(all_errors)
98            }
99        }
100        CfgExpr::Any(list) => {
101            let mut all_errors = Vec::new();
102            for subexpr in list {
103                match try_eval(cfg_evaluator, subexpr) {
104                    Ok(true) => return Ok(true),
105                    Ok(false) => {}
106                    Err(errors) => all_errors.extend(errors),
107                }
108            }
109            if all_errors.is_empty() {
110                Ok(false)
111            } else {
112                Err(all_errors)
113            }
114        }
115        CfgExpr::Not(subexpr) => match try_eval(cfg_evaluator, subexpr) {
116            Ok(value) => Ok(!value),
117            Err(errors) => Err(errors),
118        },
119    }
120}
121
122impl From<bool> for CfgResult {
123    fn from(value: bool) -> Self {
124        if value {
125            CfgResult::True
126        } else {
127            CfgResult::False
128        }
129    }
130}