1use crate::Rule;
2
3const WORD_COUNT: usize = Rule::COUNT.div_ceil(64);
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct RuleSet([u64; WORD_COUNT]);
7
8impl RuleSet {
9 pub const EMPTY: Self = Self([0; WORD_COUNT]);
10
11 pub fn all() -> Self {
12 Rule::iter().collect()
13 }
14
15 pub const fn from_rules(rules: &[Rule]) -> Self {
16 let mut words = [0; WORD_COUNT];
17 let mut index = 0;
18 while index < rules.len() {
19 let rule = rules[index] as usize;
20 let word = rule / 64;
21 let bit = rule % 64;
22 words[word] |= 1u64 << bit;
23 index += 1;
24 }
25 Self(words)
26 }
27
28 pub const fn contains(&self, rule: Rule) -> bool {
29 let word = (rule as usize) / 64;
30 let bit = (rule as usize) % 64;
31 (self.0[word] & (1u64 << bit)) != 0
32 }
33
34 pub fn insert(&mut self, rule: Rule) {
35 let word = (rule as usize) / 64;
36 let bit = (rule as usize) % 64;
37 self.0[word] |= 1u64 << bit;
38 }
39
40 pub fn remove(&mut self, rule: Rule) {
41 let word = (rule as usize) / 64;
42 let bit = (rule as usize) % 64;
43 self.0[word] &= !(1u64 << bit);
44 }
45
46 pub fn set(&mut self, rule: Rule, enabled: bool) {
47 if enabled {
48 self.insert(rule);
49 } else {
50 self.remove(rule);
51 }
52 }
53
54 pub fn union(&self, other: &Self) -> Self {
55 let mut words = [0; WORD_COUNT];
56 let mut index = 0;
57 while index < WORD_COUNT {
58 words[index] = self.0[index] | other.0[index];
59 index += 1;
60 }
61 Self(words)
62 }
63
64 pub fn subtract(&self, other: &Self) -> Self {
65 let mut words = [0; WORD_COUNT];
66 let mut index = 0;
67 while index < WORD_COUNT {
68 words[index] = self.0[index] & !other.0[index];
69 index += 1;
70 }
71 Self(words)
72 }
73
74 pub fn iter(&self) -> impl Iterator<Item = Rule> + '_ {
75 Rule::iter().filter(|rule| self.contains(*rule))
76 }
77
78 pub fn len(&self) -> usize {
79 self.0.iter().map(|word| word.count_ones() as usize).sum()
80 }
81
82 pub fn is_empty(&self) -> bool {
83 self.0.iter().all(|word| *word == 0)
84 }
85}
86
87impl Default for RuleSet {
88 fn default() -> Self {
89 Self::EMPTY
90 }
91}
92
93impl FromIterator<Rule> for RuleSet {
94 fn from_iter<T: IntoIterator<Item = Rule>>(iter: T) -> Self {
95 let mut set = Self::EMPTY;
96 for rule in iter {
97 set.insert(rule);
98 }
99 set
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn supports_insert_remove_and_iteration() {
109 let mut set = RuleSet::EMPTY;
110 assert!(set.is_empty());
111
112 set.insert(Rule::UnusedAssignment);
113 assert!(set.contains(Rule::UnusedAssignment));
114 assert_eq!(set.len(), 1);
115 assert_eq!(set.iter().collect::<Vec<_>>(), vec![Rule::UnusedAssignment]);
116
117 set.remove(Rule::UnusedAssignment);
118 assert!(set.is_empty());
119 }
120
121 #[test]
122 fn can_be_built_in_const_context() {
123 const RULES: RuleSet = RuleSet::from_rules(&[Rule::UnusedAssignment, Rule::BareRead]);
124
125 assert_eq!(
126 RULES.iter().collect::<Vec<_>>(),
127 vec![Rule::UnusedAssignment, Rule::BareRead]
128 );
129 }
130}