1use super::ConnectionId;
2use std::collections::HashMap;
3
4pub struct PatternTrie {
5 root: TrieNode,
6}
7
8impl Default for PatternTrie {
9 fn default() -> Self {
10 Self::new()
11 }
12}
13
14struct TrieNode {
15 children: HashMap<u8, Box<TrieNode>>,
16 wildcard_child: Option<Box<TrieNode>>,
17 single_char_child: Option<Box<TrieNode>>,
18 char_class_child: Option<Box<CharClassNode>>,
19 subscribers: Vec<(Vec<u8>, ConnectionId)>,
20}
21
22struct CharClassNode {
23 chars: Vec<u8>,
24 negated: bool,
25 next: Box<TrieNode>,
26}
27
28impl PatternTrie {
29 pub fn new() -> Self {
30 Self {
31 root: TrieNode::new(),
32 }
33 }
34
35 pub fn insert(&mut self, pattern: &[u8], conn_id: ConnectionId) {
36 let mut node = &mut self.root;
37 let mut i = 0;
38
39 while i < pattern.len() {
40 match pattern[i] {
41 b'*' => {
42 if node.wildcard_child.is_none() {
43 node.wildcard_child = Some(Box::new(TrieNode::new()));
44 }
45 node = node.wildcard_child.as_mut().unwrap();
46 i += 1;
47 }
48 b'?' => {
49 if node.single_char_child.is_none() {
50 node.single_char_child = Some(Box::new(TrieNode::new()));
51 }
52 node = node.single_char_child.as_mut().unwrap();
53 i += 1;
54 }
55 b'[' => {
56 let (char_class, next_i) = parse_char_class(&pattern[i..]);
57 if let Some((chars, negated)) = char_class {
58 if node.char_class_child.is_none() {
59 node.char_class_child = Some(Box::new(CharClassNode {
60 chars,
61 negated,
62 next: Box::new(TrieNode::new()),
63 }));
64 }
65 node = &mut node.char_class_child.as_mut().unwrap().next;
66 i += next_i;
67 } else {
68 node = node
69 .children
70 .entry(pattern[i])
71 .or_insert_with(|| Box::new(TrieNode::new()));
72 i += 1;
73 }
74 }
75 b'\\' if i + 1 < pattern.len() => {
76 i += 1;
77 node = node
78 .children
79 .entry(pattern[i])
80 .or_insert_with(|| Box::new(TrieNode::new()));
81 i += 1;
82 }
83 c => {
84 node = node
85 .children
86 .entry(c)
87 .or_insert_with(|| Box::new(TrieNode::new()));
88 i += 1;
89 }
90 }
91 }
92
93 node.subscribers.push((pattern.to_vec(), conn_id));
94 }
95
96 pub fn remove(&mut self, pattern: &[u8], conn_id: ConnectionId) -> bool {
97 Self::remove_from_node(&mut self.root, pattern, 0, pattern, conn_id)
98 }
99
100 fn remove_from_node(
101 node: &mut TrieNode,
102 pattern: &[u8],
103 pos: usize,
104 full_pattern: &[u8],
105 conn_id: ConnectionId,
106 ) -> bool {
107 if pos == pattern.len() {
108 let before_len = node.subscribers.len();
109 node.subscribers
110 .retain(|(p, id)| !(p == full_pattern && *id == conn_id));
111 return node.subscribers.len() < before_len;
112 }
113
114 match pattern[pos] {
115 b'*' => {
116 if let Some(ref mut child) = node.wildcard_child {
117 return Self::remove_from_node(child, pattern, pos + 1, full_pattern, conn_id);
118 }
119 }
120 b'?' => {
121 if let Some(ref mut child) = node.single_char_child {
122 return Self::remove_from_node(child, pattern, pos + 1, full_pattern, conn_id);
123 }
124 }
125 b'[' => {
126 let (char_class, next_i) = parse_char_class(&pattern[pos..]);
127 if char_class.is_some() {
128 if let Some(ref mut child) = node.char_class_child {
129 return Self::remove_from_node(
130 &mut child.next,
131 pattern,
132 pos + next_i,
133 full_pattern,
134 conn_id,
135 );
136 }
137 } else if let Some(ref mut child) = node.children.get_mut(&pattern[pos]) {
138 return Self::remove_from_node(child, pattern, pos + 1, full_pattern, conn_id);
139 }
140 }
141 b'\\' if pos + 1 < pattern.len() => {
142 if let Some(ref mut child) = node.children.get_mut(&pattern[pos + 1]) {
143 return Self::remove_from_node(child, pattern, pos + 2, full_pattern, conn_id);
144 }
145 }
146 c => {
147 if let Some(ref mut child) = node.children.get_mut(&c) {
148 return Self::remove_from_node(child, pattern, pos + 1, full_pattern, conn_id);
149 }
150 }
151 }
152
153 false
154 }
155
156 pub fn find_matches(&self, channel: &[u8]) -> Vec<(Vec<u8>, ConnectionId)> {
157 let mut matches = Vec::new();
158 self.find_in_node(&self.root, channel, 0, &mut matches);
159 matches
160 }
161
162 fn find_in_node(
163 &self,
164 node: &TrieNode,
165 channel: &[u8],
166 pos: usize,
167 matches: &mut Vec<(Vec<u8>, ConnectionId)>,
168 ) {
169 if pos == channel.len() {
170 matches.extend(node.subscribers.clone());
171
172 if let Some(ref wildcard) = node.wildcard_child {
173 matches.extend(wildcard.subscribers.clone());
174 }
175 return;
176 }
177
178 let current_char = channel[pos];
179
180 if let Some(child) = node.children.get(¤t_char) {
181 self.find_in_node(child, channel, pos + 1, matches);
182 }
183
184 if let Some(ref single) = node.single_char_child {
185 self.find_in_node(single, channel, pos + 1, matches);
186 }
187
188 if let Some(ref char_class) = node.char_class_child {
189 if self.matches_char_class(current_char, &char_class.chars, char_class.negated) {
190 self.find_in_node(&char_class.next, channel, pos + 1, matches);
191 }
192 }
193
194 if let Some(ref wildcard) = node.wildcard_child {
195 for i in pos..=channel.len() {
196 self.find_in_node(wildcard, channel, i, matches);
197 }
198 }
199 }
200
201 fn matches_char_class(&self, c: u8, chars: &[u8], negated: bool) -> bool {
202 let matches = chars.contains(&c);
203 if negated {
204 !matches
205 } else {
206 matches
207 }
208 }
209
210 pub fn clear(&mut self) {
211 self.root = TrieNode::new();
212 }
213
214 pub fn get_all_patterns(&self) -> Vec<Vec<u8>> {
215 let mut patterns = Vec::new();
216 Self::collect_patterns(&self.root, &mut patterns);
217 patterns
218 .into_iter()
219 .collect::<std::collections::HashSet<_>>()
220 .into_iter()
221 .collect()
222 }
223
224 fn collect_patterns(node: &TrieNode, patterns: &mut Vec<Vec<u8>>) {
225 for (pattern, _) in &node.subscribers {
226 patterns.push(pattern.clone());
227 }
228
229 for child in node.children.values() {
230 Self::collect_patterns(child, patterns);
231 }
232
233 if let Some(ref wildcard) = node.wildcard_child {
234 Self::collect_patterns(wildcard, patterns);
235 }
236
237 if let Some(ref single) = node.single_char_child {
238 Self::collect_patterns(single, patterns);
239 }
240
241 if let Some(ref char_class) = node.char_class_child {
242 Self::collect_patterns(&char_class.next, patterns);
243 }
244 }
245}
246
247fn parse_char_class(pattern: &[u8]) -> (Option<(Vec<u8>, bool)>, usize) {
248 if pattern.is_empty() || pattern[0] != b'[' {
249 return (None, 0);
250 }
251
252 let mut i = 1;
253 let negated = pattern.get(1) == Some(&b'^');
254 if negated {
255 i = 2;
256 }
257
258 let mut chars = Vec::new();
259 let mut escaped = false;
260
261 while i < pattern.len() {
262 if escaped {
263 chars.push(pattern[i]);
264 escaped = false;
265 } else if pattern[i] == b'\\' {
266 escaped = true;
267 } else if pattern[i] == b']' {
268 return (Some((chars, negated)), i + 1);
269 } else if pattern[i] == b'-'
270 && !chars.is_empty()
271 && i + 1 < pattern.len()
272 && pattern[i + 1] != b']'
273 {
274 let start = *chars.last().unwrap();
275 let end = pattern[i + 1];
276 for c in (start + 1)..=end {
277 chars.push(c);
278 }
279 i += 1;
280 } else {
281 chars.push(pattern[i]);
282 }
283 i += 1;
284 }
285
286 (None, 0)
287}
288
289impl TrieNode {
290 fn new() -> Self {
291 Self {
292 children: HashMap::new(),
293 wildcard_child: None,
294 single_char_child: None,
295 char_class_child: None,
296 subscribers: Vec::new(),
297 }
298 }
299}