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; 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(|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 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} 134