1 use crate::gen::{CfgEvaluator, CfgResult};
2 use crate::syntax::cfg::CfgExpr;
3 use crate::syntax::report::Errors;
4 use crate::syntax::Api;
5 use quote::quote;
6 use std::collections::BTreeSet as Set;
7 use syn::Error;
8
9 pub(super) struct UnsupportedCfgEvaluator;
10
11 impl CfgEvaluator for UnsupportedCfgEvaluator {
eval(&self, name: &str, value: Option<&str>) -> CfgResult12 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
strip( cx: &mut Errors, cfg_errors: &mut Set<String>, cfg_evaluator: &dyn CfgEvaluator, apis: &mut Vec<Api>, )20 pub(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
eval( cx: &mut Errors, cfg_errors: &mut Set<String>, cfg_evaluator: &dyn CfgEvaluator, expr: &CfgExpr, ) -> bool40 pub(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
try_eval(cfg_evaluator: &dyn CfgEvaluator, expr: &CfgExpr) -> Result<bool, Vec<Error>>59 fn 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(|string| string.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
111 impl Api {
cfg(&self) -> &CfgExpr112 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
125 impl From<bool> for CfgResult {
from(value: bool) -> Self126 fn from(value: bool) -> Self {
127 if value {
128 CfgResult::True
129 } else {
130 CfgResult::False
131 }
132 }
133 }
134