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