1use std::collections::{HashMap, HashSet};
2use std::collections::hash_map::DefaultHasher;
3use std::fmt::{Debug, Formatter};
4use std::hash::{Hash, Hasher};
5use std::sync::atomic::Ordering::Relaxed;
6use serde::Serialize;
7use serde::Deserialize;
8use log::trace;
9#[derive(Debug, Serialize, Deserialize)]
10pub struct Trie<V> {
11 children: HashMap<char, Node<V>>,
12 #[serde(default)]
13 node_count: std::sync::atomic::AtomicU32, #[serde(default)]
15 char_count: std::sync::atomic::AtomicU32,
16}
17
18impl<V> Trie<V> {
19 pub fn new() -> Trie<V> {
20 Trie {
21 children: Default::default(),
22 node_count: Default::default(),
23 char_count: Default::default()
24 }
25 }
26 pub fn insert(&mut self, text: &str,
27 optional_associated_value: Option<V>) {
28 if text.is_empty() {
29 return
30 }
31 let c = text.chars().next().unwrap();
32 if let Some(child) = self.children.get_mut(&c) {
33 child.insert(text, optional_associated_value, &self.node_count, &self.char_count) ;
34 } else {
35 self.node_count.fetch_add(1, Relaxed);
36 self.char_count.fetch_add(text.len() as u32, Relaxed);
37 self.children.insert(c, Node {
38 text: text.to_string(),
39 terminal: true,
40 children: Default::default(),
41 value: optional_associated_value,
42 visit_count: Default::default(),
43 #[cfg(feature = "tracing")]
44 node_id: gen_id(),
45 weight: text.len()
46 });
47 }
48 }
49 pub fn remove(&mut self, text: &str) {
51 let first = text.chars().next().unwrap();
52 if let Some(first) = self.children.get_mut(&first) {
53 first.remove(text, &self.node_count, &self.char_count);
54 }
55 }
56 pub fn suffix_tree(&self, prefix: &str) -> Option<&Node<V>> {
58 if prefix.is_empty() {
59 return None
60 }
61 let first = prefix.chars().next().unwrap();
62 if let Some(child) = self.children.get(&first) {
63 return child.suffix_root(prefix)
64 }
65 None
66 }
67 pub fn suffix_tree_with_matching_options(&self, prefix: &str, options: &MatchingOptions) -> Option<&Node<V>> {
69 let first = prefix.chars().next().unwrap();
70 if let Some(child) = self.children.get(&first) {
71 let tagged = options.tag(prefix);
72 return child.suffix_tree_with_options(tagged.chars.as_slice(), options);
73 }
74 None
75 }
76 pub fn get_string_suffixes(&self, prefix: &str) -> HashSet<String> {
77 let mut coll = Vec::new();
78 let mut emit = HashSet::new();
79 self.suffix_tree(prefix).map(|t| {
80 t.get_string_suffixes(true, prefix, &mut coll, &mut emit)
81 });
82 emit
83 }
84
85 pub fn get_suffixes_values(&self, prefix: &str) -> Option<Vec<Entry<V>>> {
86 let mut coll = Vec::new();
87 self.suffix_tree(prefix).map(|t| {
88 t.get_suffixes(true, prefix, &mut coll)
89 })
90 }
91
92 pub fn get_suffixes_with_matching_options(&self, prefix: &str, options: &MatchingOptions) -> Option<Vec<Entry<V>>> {
93 let mut coll = Vec::new();
94 self.suffix_tree_with_matching_options(prefix, options).map(|t| {
95 t.get_suffixes(true, prefix, &mut coll)
96 })
97 }
98}
99
100#[derive(Serialize, Deserialize)]
101pub struct Node<V> {
102 text: String,
103 terminal: bool,
104 children: HashMap<char, Node<V>>,
105 value: Option<V>,
106 #[serde(default)]
108 visit_count: std::sync::atomic::AtomicU64, #[cfg(feature = "tracing")]
110 #[serde(default = "gen_id")]
111 node_id: Option<u8>, #[serde(default)]
113 weight: usize,
114}
115
116#[cfg(feature = "tracing")]
117fn gen_id() -> Option<u8> {
118 use rand::Rng;
119 let mut rng = rand::thread_rng();
120 Some(rng.gen())
121}
122
123impl<V> Debug for Node<V> where V: Debug {
124 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
125 f.debug_struct("Node")
126 .field("text", &self.text)
127 .field("terminal", &self.terminal)
128 .field("value", &self.value).field("children", &self.children)
129 .field("nested_chars", &self.weight)
130 .finish()
131 }
132}
133
134impl<V> Node<V> {
135 pub fn new(string: &str, is_terminal: bool, value: Option<V>) -> Self {
136 Node {
137 text: string.to_string(),
138 terminal: is_terminal,
139 children: Default::default(),
140 value,
141 visit_count: Default::default(),
142 #[cfg(feature = "tracing")]
143 node_id: gen_id(),
144 weight: string.len()
145 }
146 }
147
148 pub fn remove(&mut self, text: &str,
149 node_count: &std::sync::atomic::AtomicU32,
150 char_count: &std::sync::atomic::AtomicU32) {
151 let mut position = 0;
152 let mut my_iter = self.text.chars();
153 let mut other_iter = text.chars();
154 loop {
155 let my_char = my_iter.next();
156 let other_char = other_iter.next();
157 let remaining = grapheme_slicer_until_end(text, position);
158 match (my_char, other_char) {
159 (Some(x), Some(y)) if x != y => {
162 return
164 },
165 (Some(x), Some(y)) if x == y => {
166 },
168 (Some(_), None) => {
169 return
170 },
171 (None, Some(y)) => {
172 if let Some(child) = self.children.get_mut(&y) {
173 child.remove(remaining.as_str(), node_count, char_count);
174 if child.children.len() == 0 {
175 node_count.fetch_sub(1, Relaxed);
176 char_count.fetch_sub(child.text.len() as u32, Relaxed);
177 self.weight -= child.weight;
178 if !child.terminal {
179 self.children.remove(&y); }
181 }
182 break;
183 }
184 return
186 },
187 (None, None) => {
188 if self.children.len() == 1 {
190 break
191 }
192 self.terminal = false;
194 return
195
196 },
197 _ => {}
198 }
199 position += 1;
200 }
201 if self.children.len() == 1 {
202 let (_, child) = self.children.drain().next().unwrap();
204 node_count.fetch_sub(1, Relaxed);
205 self.text = format!("{}{}", self.text, child.text);
207 self.value = child.value;
208 self.terminal = child.terminal;
209 self.children = child.children;
210 return
211 }
212 }
213
214 pub fn char_weight_of_children(&self) -> usize {
215 self.children
216 .iter()
217 .fold(0, |x, (_,y) | x + y.weight)
218 }
219
220 pub fn insert(&mut self, text: &str,
221 value: Option<V>,
222 node_count: &std::sync::atomic::AtomicU32,
223 char_count: &std::sync::atomic::AtomicU32) {
224 let mut position = 0;
225 let mut child_iter = text.chars();
226 let mut this_iter = self.text.chars();
227 loop {
228 let text_next_char = child_iter.next();
229 let this_next_char = this_iter.next();
230
231 match (text_next_char, this_next_char) {
232 (Some(x), Some(y)) if x == y => {
233 },
235 (Some(input_next), Some(this_next)) if input_next != this_next => {
236 let current_child_weight = self.char_weight_of_children();
238 let existing_remainder = grapheme_slicer_until_end(self.text.as_str(), position);
239 let mut new_node = Node {
242 text: existing_remainder.clone(),
243 terminal: self.terminal, children: Default::default(),
245 value: None,
246 visit_count: std::sync::atomic::AtomicU64::new(self.visit_count()),
247 #[cfg(feature = "std")]
248 node_id: gen_id(),
249 weight: current_child_weight + existing_remainder.len()
250 };
251 std::mem::swap(&mut new_node.children, &mut self.children);
253 std::mem::swap(&mut new_node.value, &mut self.value);
254 let first_char_of_existing_remainder = existing_remainder.chars().next().unwrap();
255 node_count.fetch_add(1, Relaxed);
257 self.children.insert(first_char_of_existing_remainder, new_node);
258
259
260 let common = grapheme_slicer_until_point(text, position);
261
262 let remainder = grapheme_slicer_until_end(text, position);
263 let input_new_node = Node {
267 text: remainder.to_string(),
268 terminal: true,
269 children: Default::default(),
270 value,
271 visit_count: std::sync::atomic::AtomicU64::new(self.visit_count()),
272 #[cfg(feature = "tracing")]
273 node_id: gen_id(),
274 weight: remainder.len()
275 };
276
277 let c = remainder.chars().next().unwrap();
278 node_count.fetch_add(1, Relaxed);
280 char_count.fetch_add(remainder.len() as u32, Relaxed);
282 self.children.insert(c, input_new_node);
283 self.text = common.to_string();
285 self.terminal = false;
286 self.weight = self.text.len() + self.char_weight_of_children();
287 return;
289
290
291
292 }
293 (None, Some(c)) => {
294 let prefix = grapheme_slicer_until_point(self.text.as_str(), position);
298
299 let remainder = grapheme_slicer_until_end(self.text.as_str(), position);
300 self.text = prefix.to_string();
301 self.terminal = true;
302 let current_child_weight = self.char_weight_of_children();
304 if let Some(child) = self.children.get_mut(&c) {
305 let taken = std::mem::take(&mut self.value);
306 self.value = value;
307
308 child.insert(remainder.as_str(), taken, node_count, char_count);
309 let new_char_weight = self.char_weight_of_children();
310 let delta = new_char_weight - current_child_weight;
311 self.weight += delta;
312 return
313 }
314 let new_node = Node {
315 text: remainder.to_string(),
316 terminal: true,
317 children: Default::default(),
318 value,
319 visit_count: std::sync::atomic::AtomicU64::new(self.visit_count()),
320 #[cfg(feature = "tracing")]
321 node_id: gen_id(),
322 weight: remainder.len()
323 };
324 node_count.fetch_add(1, Relaxed);
325 char_count.fetch_add(remainder.len() as u32, Relaxed);
326 self.children.insert(c, new_node);
327 self.terminal = true;
328 return;
329 },
330 (Some(text_next), None) => {
331 let remainder = grapheme_slicer_until_end(text, position);
332 let current_child_weight = self.char_weight_of_children();
336 if let Some(next) = self.children.get_mut(&text_next) {
337
338 next.insert(remainder.as_str(), value, node_count, char_count);
339 let new_weight_of_children = self.char_weight_of_children();
340 let delta = new_weight_of_children - current_child_weight;
341 self.weight += delta;
342 return
343 }
344 let new_node = Node {
346 text: remainder.to_string(),
347 terminal: true,
348 children: Default::default(),
349 value,
350 visit_count: std::sync::atomic::AtomicU64::new(self.visit_count()),
351 #[cfg(feature = "tracing")]
352 node_id: gen_id(),
353 weight: remainder.len()
354 };
355 self.weight += remainder.len();
356 node_count.fetch_add(1, Relaxed);
357 char_count.fetch_add(remainder.len() as u32, Relaxed);
358 self.children.insert(text_next, new_node);
359 return;
360
361 }
362 (None, None) => {
363 self.terminal = true;
364 if self.value.is_none() {
365 self.value = value;
366 }
367 return;
368 }
369 _ => {panic!("Should never be here {} {}", self.text, text )} }
371 position += 1;
372
373
374
375 }
376 }
377
378 fn match_on_treated_suffix_trees(&self, prefix: &[(Tagged, Offset)], options: &MatchingOptions) -> Vec<&Node<V>> {
379 if prefix.len() == 0 {
380 return vec![];
381 }
382 let tagged_char = &prefix.first().unwrap().0.char();
384
385 let mut v = self.children.iter().filter(|(key, _node)| {
386 key == tagged_char ||
387 options.treatments.contains_key(key)
388 } ).map(|(_, n)| {
389 n.suffix_tree_with_options(prefix, options)
390 }).flatten().collect::<Vec<_>>();
391 v.sort_by(|x,y| y.weight.cmp(&x.weight));
392 v
393 }
394
395 fn suffix_tree_with_options(&self, prefix: &[(Tagged, Offset)], options: &MatchingOptions) -> Option<&Node<V>> {
396 self.visit_count.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
400 let self_tagged = options.tag(self.text.as_str());
401 #[cfg(feature = "tracing")]
402 if true {
403 trace!("this: {:?} {:?}", self.text, self.node_id);
404 trace!("self_tagged: {:?}", self_tagged);
405 trace!("prefix: {:?}", prefix);
406 trace!("children {:?}", self.children.keys());
407 }
408
409 let this_iter = self_tagged.chars.iter();
410 let taken = prefix.iter().zip(this_iter).take_while(|((x, _),(y, _))| {x == y}).collect::<Vec<_>>().len();
411 if taken < prefix.len() {
413 }
415 if taken < self_tagged.chars.len() {
416 }
418 match taken {
419 x if x < prefix.len() && x < self_tagged.chars.len() => {
420 let (_,offset) = self_tagged.chars.get(x).unwrap();
422 let continuation = grapheme_slicer_until_end(self.text.as_str(), *offset);
423 let child_ = continuation.chars().next().unwrap();
425 let new_prefix = &prefix[x..];
426 let best_attempt = self.match_on_treated_suffix_trees(new_prefix, options).into_iter().next();
427 if let Some(child) = self.children.get(&child_) {
428 let c = child.suffix_tree_with_options(new_prefix, options);
429 match (best_attempt, c) {
430 (Some(best_attempt), Some(c)) if best_attempt.weight > c.weight => return Some(best_attempt),
431 (Some(best_attempt), _) => return Some(best_attempt),
432 (_, Some(c)) => return Some(c),
433 _ => {}
434 }
435 }
440 return best_attempt;
441 }
443 x if x == prefix.len() && x <= self_tagged.chars.len() => {
444 return Some(self) }
446 x if x == self_tagged.chars.len() && x < prefix.len() => {
447 let (last,_o) = prefix.get(x).unwrap();
448 match last {
449 Tagged::Char(c) | Tagged::Sentinel(_, c) => {
450 let new_prefix = &prefix[x..];
454 let mut treated = self.match_on_treated_suffix_trees(new_prefix, options);
455 treated.sort_by(|x,y| {
456 y.weight.partial_cmp(&x.weight).unwrap()
457 });
458 let best = treated.into_iter().next();
459
460 if let Some(child) = self.children.get(c) {
461 let c = child.suffix_tree_with_options(new_prefix, options);
462 match (best,c) {
463 (Some(best), Some(c)) if best.weight > c.weight => {
464 trace!("choose fuzzy over exact match");
465 return Some(best)}
466 (Some(best), _) => {
467 trace!("choose fuzzy (no exact match)");
468 return Some(best)
469 },
470 (_, Some(c)) => return Some(c),
471 _ => {}
472 }
473
474 }
475 return best
476 }
477
478 }
479
480 }
481 _ => {
482 return None
484 }
485 }
486 }
487
488 pub fn suffix_root(&self, prefix: &str) -> Option<&Node<V>> {
494 self.visit_count.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
496 let mut position = 0;
497 let mut this_iter = self.text.chars();
498 let mut other_iter = prefix.chars();
499 loop {
500 let this_next_char = this_iter.next();
501 let other_next_char = other_iter.next();
502 match (this_next_char, other_next_char) {
503 (Some(x), Some(y)) => {
504 if x != y {
505 if !x.is_whitespace() && !y.is_whitespace() {
507 return None
508 }
509
510 }
511 },
512 (None, Some(x)) => {
513 if let Some(next_child) = self.children.get(&x) {
514 return next_child.suffix_root(grapheme_slicer_until_end(prefix, position).as_str())
515 }
516 return None
517 }
518 (Some(x), None) => {
519 if let Some(child) = self.children.get(&x) {
520 return child.suffix_root(prefix)
521 }
522 return Some(self)
523 }
524 (None, None) => {
525 return Some(self);
526 }
527 }
528 position += 1;
529 }
530 }
531
532 fn get_suffixes<'a>(&'a self, is_root: bool, prefix: &str, collector: &mut Vec<String>) -> Vec<Entry<'a, V>> {
540 self.visit_count.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
542 if !is_root {
544 collector.push(self.text.clone());
545 } else {
546 if let Some(pos) = find_common_overlap_of_prefix_with_node(prefix, self.text.as_str()) {
547 if pos < self.text.len() {
548 collector.push(grapheme_slicer_until_end(self.text.as_str(), pos));
549 }
550 } else {
551 collector.push(self.text.clone());
552 }
553 }
554
555 let mut v: Vec<Entry<'a ,V>> = Vec::<Entry<V>>::new();
556 if self.terminal {
557 let jo = collector.join("");
558 let entry: Entry<'a, V> = Entry {
559 key: jo,
560 val: &self.value
561 };
562 v.push(entry);
563 }
564 let mut children = self.children.values();
565 while let Some(child) = children.next() {
566 let mut add = child.get_suffixes(false, prefix, collector);
567 v.append(&mut add);
568 }
569 collector.pop();
570 v
571 }
572
573 pub fn get_string_suffixes(&self, is_root: bool, prefix: &str, collector: &mut Vec<String>, emit: &mut HashSet<String>) {
574 self.visit_count.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
576 if !is_root {
577 collector.push(self.text.clone());
578 } else {
579 if let Some(pos) = find_common_overlap_of_prefix_with_node(prefix, self.text.as_str()) {
580 if pos < self.text.len() {
581 collector.push(grapheme_slicer_until_end(self.text.as_str(), pos));
582 }
583 }
584
585 }
586
587 if self.terminal {
588 let jo = collector.join("");
589 emit.insert(jo);
590 }
591 let mut children = self.children.values();
592 while let Some(child) = children.next() {
593 child.get_string_suffixes(false, prefix, collector, emit);
594 }
595 collector.pop();
596 }
597
598 fn visit_count(&self) -> u64 {
599 self.visit_count.load(std::sync::atomic::Ordering::Relaxed)
600 }
601}
602
603#[derive(Debug)]
604pub struct Entry<'a, V> {
605 pub key: String,
606 pub val: &'a Option<V>
607}
608
609pub enum CharacterSet {
610 WhiteSpaces,
612 NewLines,
614 WhiteSpacesAndNewLines,
616 CapitalizedLetters,
618
619 Char(HashSet<char>)
620
621}
622
623#[derive(Debug,Clone,PartialEq,Eq)]
624pub enum NormalizedChar {
625 Squash,
627 Char(char),
628 Sentinal(u64,char),
630}
631
632#[derive(Clone,Debug)]
633enum Tagged {
634 Char(char),
635 Sentinel(u64, char)
638}
639
640impl Tagged {
641 fn char(&self) -> &char {
642 match self {
643 Tagged::Char(x) => {x}
644 Tagged::Sentinel(_, x) => {x}
645 }
646 }
647}
648
649impl PartialEq for Tagged {
650 fn eq(&self, other: &Self) -> bool {
651 match (self,other) {
652 (Tagged::Char(c1), Tagged::Char(c2)) => c1 == c2,
653 (Tagged::Sentinel(h1, _),Tagged::Sentinel(h2, _) ) => h1 == h2,
654 _ => false
655 }
656 }
657}
658
659
660type Offset = usize;
662#[derive(Clone,Debug)]
664struct TaggedString {
665 chars: Vec<(Tagged, Offset)>
666}
667
668impl TaggedString {
669 #[allow(dead_code)]
672 fn new(str: &str) -> Self {
673 Self {
674 chars: str.chars().enumerate().map(|(offset, char)| {
675 (Tagged::Char(char), offset)
676 }).collect()
677 }
678 }
679}
680
681
682impl From<Vec<NormalizedChar>> for TaggedString {
684 fn from(chars: Vec<NormalizedChar>) -> Self {
685 let tagged = chars.into_iter().enumerate().flat_map(|(offset,y)| {
686 match y {
687 NormalizedChar::Squash => {None}
688 NormalizedChar::Char(x) => {Some((Tagged::Char(x), offset))}
689 NormalizedChar::Sentinal(hash, char) => {Some((Tagged::Sentinel(hash,char), offset))}
690 }
691 }).collect();
692 Self {
693 chars: tagged
694 }
695 }
696}
697
698impl CharacterSet {
699 pub fn normalized_char(&self, char: char) -> NormalizedChar {
700 match self {
701 CharacterSet::WhiteSpaces if char.is_whitespace() => {
702 NormalizedChar::Squash
703 }
704 CharacterSet::NewLines if char == '\n' => { NormalizedChar::Squash}
705 CharacterSet::WhiteSpacesAndNewLines if char == '\n' || char == ' '=> { NormalizedChar::Squash}
706 CharacterSet::CapitalizedLetters => { NormalizedChar::Char(char.to_uppercase().next().unwrap_or(char))}
707 CharacterSet::Char(x) if x.contains(&char)=> {
708 let mut v = x.iter().collect::<Vec<_>>();
709 v.sort(); let mut s = DefaultHasher::new();
711
712 v.hash(&mut s);
713 NormalizedChar::Sentinal(s.finish(), char)
714 }
715 _ => NormalizedChar::Char(char)
716 }
717 }
718}
719
720fn encode(str: &str, treatments: &HashMap<char, CharacterSet>) -> Vec<NormalizedChar> {
721 str.chars().map(|c| {
722 treatments.get(&c).map(|t| t.normalized_char(c)).unwrap_or_else(|| NormalizedChar::Char(c))
723 }
724 ).collect::<Vec<_>>()
725}
726
727fn grapheme_slicer_until_end(str: &str, from:usize) -> String {
731 let temp = str.chars().collect::<Vec<_>>();
733 let x = &temp.as_slice()[from..temp.len()];
734 x.iter().collect()
735}
736
737fn grapheme_slicer_until_point(str: &str, until: usize) -> String {
738
739 let temp = str.chars().collect::<Vec<_>>();
740 let x = &temp.as_slice()[0..until];
741 x.iter().collect()
742}
743
744#[test]
745fn test_shitty_slicer() {
746 let text = "🤡abcded🤡";
747 let pref = grapheme_slicer_until_point(text, 4);
748 assert_eq!(pref, "🤡abc");
749}
750pub struct MatchingOptions {
754 treatments: HashMap<char, CharacterSet>, }
756
757impl MatchingOptions {
758 pub fn exact() -> Self {
760 Self {
761 treatments: Default::default()
762 }
763 }
764 pub fn ignoring_white_space() -> Self {
766 let mut treatments = HashMap::new();
767 treatments.insert(' ', CharacterSet::WhiteSpaces);
768 treatments.insert('\t', CharacterSet::WhiteSpaces);
769 Self {
770 treatments
771 }
772 }
773
774 pub fn ignoring_new_lines() -> Self {
776 let mut treatments = HashMap::new();
777 treatments.insert('\n', CharacterSet::WhiteSpaces);
778 Self {
779 treatments
780 }
781 }
782 pub fn ignoring_white_space_and_new_lines() -> Self {
784 let mut treatments = HashMap::new();
785 treatments.insert(' ', CharacterSet::WhiteSpaces);
786 treatments.insert('\t', CharacterSet::WhiteSpaces);
787 treatments.insert('\n', CharacterSet::WhiteSpaces);
788 Self {
789 treatments
790 }
791 }
792
793 fn tag(&self, str: &str) -> TaggedString {
794 let encoded = encode(str, &self.treatments);
795 TaggedString::from(encoded)
796 }
797}
798
799fn find_common_overlap_of_prefix_with_node(prefix: &str, node: &str) -> Option<usize>{
800 for offset in (0..prefix.len()).rev() {
804 let str = grapheme_slicer_until_end(&prefix, offset);
805 if node.starts_with(str.as_str()) {
806 return Some(str.len())
807 }
808 }
809 None
810
811}
812
813
814#[test]
815fn test_squashing() {
816 let node_text = " abc def iop \t\t\t qwe ";
817 let input = "abc def iop qwe";
818
819 let internal = MatchingOptions::ignoring_white_space();
820 let nt1 = internal.tag(node_text);
821 let nt2 = internal.tag(input);
822
823 println!("{:?}", nt1);
824 println!("{:?}", nt2);
825}
826
827#[test]
828fn test_empty() {
829 let mut trie: Trie<String> = Trie::new();
830 trie.insert("", None);
831 let results = trie.get_suffixes_values("");
832 assert!(results.is_none());
833 trie.insert("romanus", None);
834 let results = trie.get_suffixes_values("");
835 assert!(results.is_none());
836 trie.insert("romulus", None);
837 let results = trie.get_suffixes_values("");
838 assert!(results.is_none());
839 trie.insert("rubens", None);
840 let results = trie.get_suffixes_values("");
841 assert!(results.is_none());
842 trie.insert("ruber", None);
843 let results = trie.get_suffixes_values("");
844 assert!(results.is_none());
845 trie.insert("rubicon", None);
846 let results = trie.get_suffixes_values("");
847 assert!(results.is_none());
848 trie.insert("rubicundus", None);
849 let results = trie.get_suffixes_values("");
850 assert!(results.is_none());
851}