rusty_bind_parser/
utils.rs

1use std::collections::HashSet;
2
3use cfg_expr::targets::TargetInfo;
4use cfg_expr::{Expression, Predicate};
5use syn::Attribute;
6
7use crate::binding_module::CargoFeature;
8
9pub(crate) fn is_primitive(name: &str) -> bool {
10    name == "u8"
11        || name == "u16"
12        || name == "u32"
13        || name == "u64"
14        || name == "i8"
15        || name == "i16"
16        || name == "i32"
17        || name == "i64"
18        || name == "f32"
19        || name == "f64"
20        || name == "isize"
21        || name == "usize"
22        || name == "bool"
23}
24
25#[derive(Debug, Clone)]
26pub struct BuildContext {
27    current_target_info: &'static TargetInfo,
28    features: Vec<CargoFeature>,
29    target_features: Vec<String>,
30}
31
32impl BuildContext {
33    pub fn new(
34        current_target_info: &'static TargetInfo,
35        features: Vec<CargoFeature>,
36        target_features: Vec<String>,
37    ) -> Self {
38        Self {
39            current_target_info,
40            features,
41            target_features,
42        }
43    }
44
45    pub(crate) fn check_cfg_attrs<T>(&self, attrs: &T) -> bool
46    where
47        for<'a> &'a T: IntoIterator<Item = &'a Attribute>,
48    {
49        attrs
50            .into_iter()
51            .map(|attr| {
52                let cfg = match &attr.meta {
53                    syn::Meta::List(val) => val.tokens.to_string(),
54                    _ => panic!("Invalid cfg attribute"),
55                };
56
57                let required_cfg = Expression::parse(&cfg).expect("Invalid cfg attribute");
58
59                required_cfg.eval(|pred| match pred {
60                    Predicate::Target(tp) => tp.matches(self.current_target_info),
61                    Predicate::Feature(feature) => self
62                        .features
63                        .iter()
64                        .any(|val| *val == CargoFeature::new(feature)),
65                    Predicate::TargetFeature(target_feature) => {
66                        self.target_features.iter().any(|val| val == target_feature)
67                    }
68                    _ => panic!("Unsupported cfg value"),
69                })
70            })
71            .all(|el| el)
72    }
73}
74
75#[derive(Debug, Default)]
76struct NameTracker {
77    known: HashSet<String>,
78    unknown: HashSet<String>,
79}
80
81impl NameTracker {
82    pub(crate) fn add_unknown(&mut self, name: String) {
83        if !self.known.iter().any(|v| v == &name) {
84            self.unknown.insert(name);
85        }
86    }
87
88    pub(crate) fn add_known(&mut self, name: String) {
89        self.unknown.retain(|v| v != &name);
90        self.known.insert(name);
91    }
92}
93
94#[derive(Debug, Default)]
95pub struct NamesTracker {
96    traits: NameTracker,
97    custom_types: NameTracker,
98}
99
100impl NamesTracker {
101    pub(crate) fn add_known_trait(&mut self, name: String) {
102        self.traits.add_known(name)
103    }
104
105    pub(crate) fn add_unknown_trait(&mut self, name: String) {
106        self.traits.add_unknown(name)
107    }
108
109    pub(crate) fn add_known_custom_type(&mut self, name: String) {
110        self.custom_types.add_known(name)
111    }
112
113    pub(crate) fn add_unknown_custom_type(&mut self, name: String) {
114        self.custom_types.add_unknown(name)
115    }
116
117    pub(crate) fn get_unknown(&self) -> Vec<String> {
118        let mut result = vec![];
119        result.extend(self.custom_types.unknown.iter().cloned());
120        result.extend(self.traits.unknown.iter().cloned());
121        result
122    }
123}
124
125#[cfg(test)]
126pub(crate) mod helpers {
127    use cfg_expr::targets::get_builtin_target_by_triple;
128    use syn::ItemEnum;
129
130    use crate::enum_helpers::get_enums_from_module;
131    use crate::utils::BuildContext;
132
133    pub fn get_context() -> BuildContext {
134        BuildContext {
135            current_target_info: get_builtin_target_by_triple("x86_64-apple-darwin").unwrap(),
136            features: vec![],
137            target_features: vec![],
138        }
139    }
140
141    pub fn get_enum_item() -> ItemEnum {
142        let rust_code = "
143mod ffi {
144    enum En1 {
145        V1,
146        V2,
147    }
148}
149        ";
150        let context = get_context();
151        let module = syn::parse_str(rust_code).unwrap();
152        get_enums_from_module(&module, &context).unwrap().remove(0)
153    }
154}