1use std::collections::HashMap;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum TrieResult {
15 Failed,
17 Prefix,
19 Exists,
21}
22
23#[derive(Debug, Clone)]
41pub struct Trie<V> {
42 children: HashMap<char, Trie<V>>,
43 value: Option<V>,
44}
45
46impl<V> Default for Trie<V> {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52impl<V> Trie<V> {
53 pub fn new() -> Self {
55 Self {
56 children: HashMap::new(),
57 value: None,
58 }
59 }
60
61 pub fn insert(&mut self, key: &str, value: V) {
67 let mut current = self;
68 for ch in key.chars() {
69 current = current.children.entry(ch).or_insert_with(Trie::new);
70 }
71 current.value = Some(value);
72 }
73
74 pub fn get(&self, key: &str) -> Option<&V> {
78 let mut current = self;
79 for ch in key.chars() {
80 match current.children.get(&ch) {
81 Some(child) => current = child,
82 None => return None,
83 }
84 }
85 current.value.as_ref()
86 }
87
88 pub fn in_trie(&self, key: &str) -> (TrieResult, Option<&V>) {
97 if key.is_empty() {
98 return (TrieResult::Failed, None);
99 }
100
101 let mut current = self;
102 for ch in key.chars() {
103 match current.children.get(&ch) {
104 Some(child) => current = child,
105 None => return (TrieResult::Failed, None),
106 }
107 }
108
109 if current.value.is_some() {
110 (TrieResult::Exists, current.value.as_ref())
111 } else {
112 (TrieResult::Prefix, None)
113 }
114 }
115
116 pub fn in_trie_char(&self, ch: char) -> (TrieResult, Option<&Trie<V>>) {
125 match self.children.get(&ch) {
126 Some(child) => {
127 if child.value.is_some() {
128 (TrieResult::Exists, Some(child))
129 } else {
130 (TrieResult::Prefix, Some(child))
131 }
132 }
133 None => (TrieResult::Failed, None),
134 }
135 }
136
137 pub fn get_child(&self, ch: char) -> Option<&Trie<V>> {
139 self.children.get(&ch)
140 }
141
142 pub fn has_value(&self) -> bool {
144 self.value.is_some()
145 }
146
147 pub fn value(&self) -> Option<&V> {
149 self.value.as_ref()
150 }
151
152 pub fn is_empty(&self) -> bool {
154 self.children.is_empty() && self.value.is_none()
155 }
156
157 pub fn keys(&self) -> Vec<String> {
159 let mut result = Vec::new();
160 self.collect_keys(String::new(), &mut result);
161 result
162 }
163
164 fn collect_keys(&self, prefix: String, result: &mut Vec<String>) {
165 if self.value.is_some() {
166 result.push(prefix.clone());
167 }
168 for (ch, child) in &self.children {
169 let mut new_prefix = prefix.clone();
170 new_prefix.push(*ch);
171 child.collect_keys(new_prefix, result);
172 }
173 }
174}
175
176pub fn new_trie<V, I>(keywords: I) -> Trie<V>
190where
191 I: IntoIterator<Item = (String, V)>,
192{
193 let mut trie = Trie::new();
194 for (key, value) in keywords {
195 trie.insert(&key, value);
196 }
197 trie
198}
199
200pub fn new_trie_from_keys<I, S>(keywords: I) -> Trie<()>
213where
214 I: IntoIterator<Item = S>,
215 S: AsRef<str>,
216{
217 let mut trie = Trie::new();
218 for key in keywords {
219 trie.insert(key.as_ref(), ());
220 }
221 trie
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn test_new_trie() {
230 let trie = new_trie([
231 ("bla".to_string(), ()),
232 ("foo".to_string(), ()),
233 ("blab".to_string(), ()),
234 ]);
235
236 assert_eq!(trie.in_trie("bla").0, TrieResult::Exists);
237 assert_eq!(trie.in_trie("blab").0, TrieResult::Exists);
238 assert_eq!(trie.in_trie("foo").0, TrieResult::Exists);
239 }
240
241 #[test]
242 fn test_in_trie_failed() {
243 let trie = new_trie_from_keys(["cat"]);
244 assert_eq!(trie.in_trie("bob").0, TrieResult::Failed);
245 }
246
247 #[test]
248 fn test_in_trie_prefix() {
249 let trie = new_trie_from_keys(["cat"]);
250 assert_eq!(trie.in_trie("ca").0, TrieResult::Prefix);
251 }
252
253 #[test]
254 fn test_in_trie_exists() {
255 let trie = new_trie_from_keys(["cat"]);
256 assert_eq!(trie.in_trie("cat").0, TrieResult::Exists);
257 }
258
259 #[test]
260 fn test_empty_key() {
261 let trie = new_trie_from_keys(["cat"]);
262 assert_eq!(trie.in_trie("").0, TrieResult::Failed);
263 }
264
265 #[test]
266 fn test_get_value() {
267 let trie = new_trie([
268 ("foo".to_string(), 42),
269 ("bar".to_string(), 100),
270 ]);
271
272 assert_eq!(trie.get("foo"), Some(&42));
273 assert_eq!(trie.get("bar"), Some(&100));
274 assert_eq!(trie.get("baz"), None);
275 assert_eq!(trie.get("fo"), None); }
277
278 #[test]
279 fn test_in_trie_char() {
280 let trie = new_trie_from_keys(["cat", "car"]);
281
282 let (result, subtrie) = trie.in_trie_char('c');
284 assert_eq!(result, TrieResult::Prefix);
285 assert!(subtrie.is_some());
286
287 let subtrie = subtrie.unwrap();
289 let (result, subtrie) = subtrie.in_trie_char('a');
290 assert_eq!(result, TrieResult::Prefix);
291 assert!(subtrie.is_some());
292
293 let subtrie = subtrie.unwrap();
295 let (result, _) = subtrie.in_trie_char('t');
296 assert_eq!(result, TrieResult::Exists);
297
298 let (result, subtrie) = trie.in_trie_char('d');
300 assert_eq!(result, TrieResult::Failed);
301 assert!(subtrie.is_none());
302 }
303
304 #[test]
305 fn test_keys() {
306 let trie = new_trie_from_keys(["cat", "car", "card"]);
307 let mut keys = trie.keys();
308 keys.sort();
309 assert_eq!(keys, vec!["car", "card", "cat"]);
310 }
311
312 #[test]
313 fn test_unicode() {
314 let trie = new_trie_from_keys(["cafe", "caf\u{00e9}"]); assert_eq!(trie.in_trie("cafe").0, TrieResult::Exists);
316 assert_eq!(trie.in_trie("caf\u{00e9}").0, TrieResult::Exists);
317 }
318
319 #[test]
320 fn test_overlapping_prefixes() {
321 let trie = new_trie_from_keys(["bla", "blab"]);
323
324 assert_eq!(trie.in_trie("bla").0, TrieResult::Exists);
326
327 assert_eq!(trie.in_trie("blab").0, TrieResult::Exists);
329
330 assert_eq!(trie.in_trie("bl").0, TrieResult::Prefix);
332 }
333}