1 | use super::*; |
2 | |
3 | #[derive (Debug, Default)] |
4 | pub struct Filter(Vec<(String, bool)>); |
5 | |
6 | impl Filter { |
7 | pub fn new(reader: &Reader, include: &[&str], exclude: &[&str]) -> Self { |
8 | let mut rules = vec![]; |
9 | |
10 | for filter in include { |
11 | push_filter(reader, &mut rules, filter, true); |
12 | } |
13 | |
14 | for filter in exclude { |
15 | push_filter(reader, &mut rules, filter, false) |
16 | } |
17 | |
18 | debug_assert!(!rules.is_empty()); |
19 | |
20 | rules.sort_unstable_by(|left, right| { |
21 | let left = (left.0.len(), !left.1); |
22 | let right = (right.0.len(), !right.1); |
23 | left.cmp(&right).reverse() |
24 | }); |
25 | |
26 | Self(rules) |
27 | } |
28 | |
29 | pub fn includes_namespace(&self, namespace: &str) -> bool { |
30 | for rule in &self.0 { |
31 | if rule.1 { |
32 | // include |
33 | if namespace_starts_with(&rule.0, namespace) { |
34 | return true; |
35 | } |
36 | if namespace_starts_with(namespace, &rule.0) { |
37 | return true; |
38 | } |
39 | } else { |
40 | // exclude |
41 | if namespace_starts_with(namespace, &rule.0) { |
42 | return false; |
43 | } |
44 | } |
45 | } |
46 | |
47 | false |
48 | } |
49 | |
50 | pub fn includes_type_name(&self, name: TypeName) -> bool { |
51 | for rule in &self.0 { |
52 | if match_type_name(&rule.0, name.namespace(), name.name()) { |
53 | return rule.1; |
54 | } |
55 | } |
56 | |
57 | false |
58 | } |
59 | |
60 | pub fn excludes_type_name(&self, name: TypeName) -> bool { |
61 | for rule in &self.0 { |
62 | if match_type_name(&rule.0, name.namespace(), name.name()) { |
63 | return !rule.1; |
64 | } |
65 | } |
66 | |
67 | false |
68 | } |
69 | } |
70 | |
71 | fn push_filter(reader: &Reader, rules: &mut Vec<(String, bool)>, filter: &str, include: bool) { |
72 | if reader.contains_key(filter) { |
73 | rules.push((filter.to_string(), include)); |
74 | return; |
75 | } |
76 | |
77 | if let Some((namespace, name)) = filter.rsplit_once('.' ) { |
78 | if reader.with_full_name(namespace, name).next().is_some() { |
79 | rules.push((filter.to_string(), include)); |
80 | return; |
81 | } |
82 | } |
83 | |
84 | let mut pushed = false; |
85 | |
86 | for (namespace, types) in reader.iter() { |
87 | if types.get(filter).is_some() { |
88 | rules.push((format!(" {namespace}. {filter}" ), include)); |
89 | pushed = true; |
90 | } |
91 | } |
92 | |
93 | if pushed { |
94 | return; |
95 | } |
96 | |
97 | if reader |
98 | .keys() |
99 | .any(|namespace| namespace_starts_with(namespace, filter)) |
100 | { |
101 | rules.push((filter.to_string(), include)); |
102 | return; |
103 | } |
104 | |
105 | panic!("type not found: ` {filter}`" ); |
106 | } |
107 | |
108 | fn match_type_name(rule: &str, namespace: &str, name: &str) -> bool { |
109 | if rule.len() <= namespace.len() { |
110 | return namespace.starts_with(rule); |
111 | } |
112 | |
113 | if !rule.starts_with(namespace) { |
114 | return false; |
115 | } |
116 | |
117 | if rule.as_bytes()[namespace.len()] != b'.' { |
118 | return false; |
119 | } |
120 | |
121 | name == &rule[namespace.len() + 1..] |
122 | } |
123 | |