Skip to main content

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            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}