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
use std::collections::{HashMap, HashSet};
use regex::Regex;
use {NodeID, re_matches};
pub struct TagDB {
node_to_tags: HashMap<NodeID, HashSet<String>>,
tag_to_nodes: HashMap<String, HashSet<NodeID>>,
}
impl Default for TagDB {
fn default() -> TagDB {
TagDB {
node_to_tags: HashMap::new(),
tag_to_nodes: HashMap::new(),
}
}
}
impl TagDB {
pub fn reindex(&mut self, node: NodeID, text: String) {
lazy_static! {
static ref RE_TAG_KEY: Regex = Regex::new(r"#([^\s=]+)*").unwrap();
static ref RE_TAG_KEY_VALUE: Regex = Regex::new(r"#(\S+)*").unwrap();
}
self.remove(node);
self.node_to_tags.insert(node, HashSet::new());
let tags = re_matches::<String>(&RE_TAG_KEY_VALUE, &*text);
for tag in &tags {
if let Some(mut tags) = self.node_to_tags.get_mut(&node) {
tags.insert(tag.clone());
}
let mut nodes = self.tag_to_nodes
.remove(tag)
.unwrap_or_else(|| HashSet::new());
nodes.insert(node);
self.tag_to_nodes.insert(tag.clone(), nodes);
}
if text.contains('=') {
let tags = re_matches::<String>(&RE_TAG_KEY, &*text);
for tag in &tags {
if let Some(mut tags) = self.node_to_tags.get_mut(&node) {
tags.insert(tag.clone());
}
let mut nodes = self.tag_to_nodes
.remove(tag)
.unwrap_or_else(|| HashSet::new());
nodes.insert(node);
self.tag_to_nodes.insert(tag.clone(), nodes);
}
}
}
pub fn remove(&mut self, node: NodeID) {
if let Some(tags_to_clean) = self.node_to_tags.remove(&node) {
for tag in &tags_to_clean {
if let Some(mut nodes) = self.tag_to_nodes.get_mut(tag) {
nodes.remove(&node);
}
}
}
}
pub fn tag_to_nodes(&self, tag: &str) -> Vec<NodeID> {
let mut res = self.tag_to_nodes
.get(&tag.to_owned())
.map(|set| set.clone().into_iter().collect())
.unwrap_or_else(|| vec![]);
res.sort();
res
}
}
#[test]
fn test_basic_func() {
let mut tdb = TagDB::default();
tdb.reindex(1, "hey #1 #there #yes=4".to_owned());
tdb.reindex(2, "hey #1=2 #yo #yes".to_owned());
tdb.reindex(3, "hey #1 #yes=ok".to_owned());
tdb.reindex(4, "hey #$".to_owned());
assert_eq!(tdb.tag_to_nodes("there"), vec![1]);
assert_eq!(tdb.tag_to_nodes("1"), vec![1, 2, 3]);
assert_eq!(tdb.tag_to_nodes("yes"), vec![1, 2, 3]);
assert_eq!(tdb.tag_to_nodes("yes=ok"), vec![3]);
assert_eq!(tdb.tag_to_nodes("$"), vec![4]);
}