about summary refs log tree commit diff stats
path: root/sys/nixpkgs/pkgs/lf-make-map/src/mapping/map_tree.rs
blob: 44165ed1320fd0c5ad2ff77e252a18968eceec06 (plain) (blame)
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use std::collections::HashMap;

use super::{error, Mapping};

/// A prefix tree
pub struct MappingTree {
    root: Node,
}

#[derive(Clone)]
pub struct Node {
    children: HashMap<char, Node>,
    value: Option<Mapping>,

    /// The key needed to get to this node
    location: String,
}

impl MappingTree {
    pub fn new() -> Self {
        Self {
            root: Node::new(String::new(), None),
        }
    }

    /// Returns the node at the key, otherwise None
    pub fn get(&self, key: &str) -> Option<&Node> {
        let mut current_node = &self.root;
        for ch in key.chars() {
            current_node = current_node.children.get(&ch)?
        }

        Some(current_node)
    }
    /// Returns the node at the key, otherwise None. The node can be changed
    pub fn get_mut(&mut self, key: &str) -> Option<&mut Node> {
        let mut current_node = &mut self.root;
        for ch in key.chars() {
            current_node = current_node.children.get_mut(&ch)?
        }

        Some(current_node)
    }

    /// Returns the node at the key, otherwise the last node that matched.
    pub fn try_get(&self, key: &str) -> &Node {
        let mut current_node = &self.root;
        for ch in key.chars() {
            if let Some(node) = current_node.children.get(&ch) {
                current_node = node;
            } else {
                return current_node;
            }
        }

        current_node
    }

    pub fn insert(&mut self, key: &str, mapping: Mapping) -> Result<(), error::Error> {
        let node = self.try_get(key).clone();
        if node.location.as_str() != key {
            let needed_nodes_key = key.trim_start_matches(node.location.as_str());
            let needed_nodes_length = needed_nodes_key.chars().count();

            let mut current_node = self
                .get_mut(&node.location)
                .expect("This should always exists");
            let mut current_location = node.location.clone();
            let mut counter = 0;

            for ch in needed_nodes_key.chars() {
                current_location.push(ch);

                let next_node = if counter == needed_nodes_length {
                    Node::new(current_location.clone(), Some(mapping.clone()))
                } else {
                    Node::new(current_location.clone(), None)
                };

                current_node.children.insert(ch, next_node);
                current_node = current_node
                    .children
                    .get_mut(&ch)
                    .expect("Was just inserted");
                counter += 1;
            }
        } else {
            return Err(error::Error::NodeExits(key.to_owned()));
        }

        Ok(())
    }
}

impl Node {
    pub fn new(location: String, mapping: Option<Mapping>) -> Self {
        Self {
            children: HashMap::new(),
            location,
            value: mapping,
        }
    }
}