1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/// Overview: Tree to match substring with rule.
use std::collections::HashMap;

use super::node::Node;
use super::rule::Rule;

pub struct Tree {
    rules: Vec<Rule>,
    rules_from_chars: Vec<Vec<char>>,
    nodes: Vec<Node>,
}

impl Tree {
    pub fn from(rules: Vec<Rule>) -> Tree {
        // Improve performance for custom string matching.
        let rules_from_chars = rules
            .iter()
            .map(|rule| rule.from.chars().collect())
            .collect();

        let mut tree = Tree {
            rules,
            rules_from_chars,
            nodes: Vec::new(),
        };

        tree.nodes.push(Node {
            rule_index: None,
            children_map: HashMap::new(),
        });

        for index in 0..tree.rules.len() {
            tree.add(index);
        }

        tree
    }

    fn add(&mut self, rule_index: usize) {
        let from = &self.rules_from_chars[rule_index];
        let mut current_index = 0usize;

        for ch in from {
            current_index = match self.nodes[current_index].children_map.get(ch) {
                Some(&index) => index,
                None => {
                    // "index" will be the index of following node.
                    let index = self.nodes.len();
                    self.nodes[current_index].children_map.insert(*ch, index);
                    self.nodes.push(Node {
                        rule_index: None,
                        children_map: HashMap::new(),
                    });
                    index
                }
            };
        }

        self.nodes[current_index].rule_index = Some(rule_index);
    }

    pub fn query(&self, chars: &[char], start: usize, chars_len: usize) -> Option<(&str, usize)> {
        let mut pivot = start;
        let mut depth = 0usize;
        let mut current_index = 0usize;
        let mut rule_index: Option<usize> = None;

        while pivot < chars_len {
            match self.nodes[current_index].children_map.get(&chars[pivot]) {
                Some(&index) => {
                    current_index = index;
                    if let Some(i) = self.nodes[current_index].rule_index {
                        rule_index = Some(i);
                    }
                }
                None => break,
            }

            pivot += 1;
            depth += 1;
        }

        rule_index.map(|index| (self.rules[index].to, depth))
    }
}