feox_server/pubsub/
pattern.rs

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(&current_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            matches.extend(wildcard.subscribers.clone());
196
197            for i in pos..=channel.len() {
198                self.find_in_node(wildcard, channel, i, matches);
199            }
200        }
201    }
202
203    fn matches_char_class(&self, c: u8, chars: &[u8], negated: bool) -> bool {
204        let matches = chars.contains(&c);
205        if negated {
206            !matches
207        } else {
208            matches
209        }
210    }
211
212    pub fn clear(&mut self) {
213        self.root = TrieNode::new();
214    }
215
216    pub fn get_all_patterns(&self) -> Vec<Vec<u8>> {
217        let mut patterns = Vec::new();
218        Self::collect_patterns(&self.root, &mut patterns);
219        patterns
220            .into_iter()
221            .collect::<std::collections::HashSet<_>>()
222            .into_iter()
223            .collect()
224    }
225
226    fn collect_patterns(node: &TrieNode, patterns: &mut Vec<Vec<u8>>) {
227        for (pattern, _) in &node.subscribers {
228            patterns.push(pattern.clone());
229        }
230
231        for child in node.children.values() {
232            Self::collect_patterns(child, patterns);
233        }
234
235        if let Some(ref wildcard) = node.wildcard_child {
236            Self::collect_patterns(wildcard, patterns);
237        }
238
239        if let Some(ref single) = node.single_char_child {
240            Self::collect_patterns(single, patterns);
241        }
242
243        if let Some(ref char_class) = node.char_class_child {
244            Self::collect_patterns(&char_class.next, patterns);
245        }
246    }
247}
248
249fn parse_char_class(pattern: &[u8]) -> (Option<(Vec<u8>, bool)>, usize) {
250    if pattern.is_empty() || pattern[0] != b'[' {
251        return (None, 0);
252    }
253
254    let mut i = 1;
255    let negated = pattern.get(1) == Some(&b'^');
256    if negated {
257        i = 2;
258    }
259
260    let mut chars = Vec::new();
261    let mut escaped = false;
262
263    while i < pattern.len() {
264        if escaped {
265            chars.push(pattern[i]);
266            escaped = false;
267        } else if pattern[i] == b'\\' {
268            escaped = true;
269        } else if pattern[i] == b']' {
270            return (Some((chars, negated)), i + 1);
271        } else if pattern[i] == b'-'
272            && !chars.is_empty()
273            && i + 1 < pattern.len()
274            && pattern[i + 1] != b']'
275        {
276            let start = *chars.last().unwrap();
277            let end = pattern[i + 1];
278            for c in (start + 1)..=end {
279                chars.push(c);
280            }
281            i += 1;
282        } else {
283            chars.push(pattern[i]);
284        }
285        i += 1;
286    }
287
288    (None, 0)
289}
290
291impl TrieNode {
292    fn new() -> Self {
293        Self {
294            children: HashMap::new(),
295            wildcard_child: None,
296            single_char_child: None,
297            char_class_child: None,
298            subscribers: Vec::new(),
299        }
300    }
301}