Skip to content

Commit e10b125

Browse files
committed
feat(libredirectionio): wip rework router and regex tree
1 parent e8c0632 commit e10b125

28 files changed

+3100
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ scraper = "0.17.1"
4444
serde = { version = "1.0", features = ["derive"] }
4545
serde_json = "1.0.107"
4646
stderrlog = "0.5.4"
47+
tracing = "0.1.37"
4748
url = "2.4.1"
4849

4950
[dev-dependencies]

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@ mod callback_log;
2525
mod ffi;
2626
#[cfg(not(target_arch = "wasm32"))]
2727
mod ffi_helpers;
28+
mod regex_radix_tree_new;
29+
mod router_new;

src/regex_radix_tree_new/item.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use super::leaf::Leaf;
2+
use super::node::Node;
3+
4+
#[derive(Debug)]
5+
pub enum Item<V> {
6+
Empty(bool),
7+
Node(Node<V>),
8+
Leaf(Leaf<V>),
9+
}
10+
11+
impl<V> Item<V> {
12+
/// Insert a new item into this node
13+
pub fn insert(self, regex: &str, id: String, item: V) -> Item<V> {
14+
match self {
15+
Item::Empty(ignore_case) => Item::Leaf(Leaf::new(regex, id, item, ignore_case)),
16+
Item::Node(node) => node.insert(regex, id, item),
17+
Item::Leaf(leaf) => leaf.insert(regex, id, item),
18+
}
19+
}
20+
21+
/// Find values associated to this haystack
22+
pub fn find(&self, haystack: &str) -> Vec<&V> {
23+
match self {
24+
Item::Empty(_) => Vec::new(),
25+
Item::Node(node) => node.find(haystack),
26+
Item::Leaf(leaf) => leaf.find(haystack),
27+
}
28+
}
29+
30+
pub fn get(&self, regex: &str) -> Vec<&V> {
31+
match self {
32+
Item::Empty(_) => Vec::new(),
33+
Item::Node(node) => node.get(regex),
34+
Item::Leaf(leaf) => leaf.get(regex),
35+
}
36+
}
37+
38+
pub fn get_mut(&mut self, regex: &str) -> Vec<&mut V> {
39+
match self {
40+
Item::Empty(_) => Vec::new(),
41+
Item::Node(node) => node.get_mut(regex),
42+
Item::Leaf(leaf) => leaf.get_mut(regex),
43+
}
44+
}
45+
46+
/// Remove an item on this tree
47+
///
48+
/// This method returns true if there is no more data so it can be cleaned up
49+
pub fn remove(self, id: &str) -> (Self, Option<V>) {
50+
match self {
51+
Item::Empty(_) => (self, None),
52+
Item::Node(node) => node.remove(id),
53+
Item::Leaf(leaf) => leaf.remove(id),
54+
}
55+
}
56+
57+
/// Length of node
58+
pub fn len(&self) -> usize {
59+
match self {
60+
Item::Empty(_) => 0,
61+
Item::Node(node) => node.len(),
62+
Item::Leaf(leaf) => leaf.len(),
63+
}
64+
}
65+
66+
pub fn regex(&self) -> &str {
67+
match self {
68+
Item::Empty(_) => "",
69+
Item::Node(node) => node.regex(),
70+
Item::Leaf(leaf) => leaf.regex(),
71+
}
72+
}
73+
74+
/// Cache current regex according to a limit and a level
75+
///
76+
/// This method must return new limit of element cached (passed limit minus number of element cached)
77+
/// which allow other node to avoid caching extra node
78+
///
79+
/// Implementation must not cache item if limit is equal to 0
80+
/// Implementation must not cache item if not caching on the current node level
81+
///
82+
/// Level argument allow to build cache on first level of the tree by priority
83+
/// Implementation must retain at which level this node is build and not do any caching
84+
/// if we are not on the current level
85+
pub fn cache(&mut self, left: u64, max_level: u64, current_level: u64) -> u64 {
86+
if left <= 0 {
87+
return left;
88+
}
89+
90+
if current_level > max_level {
91+
return left;
92+
}
93+
94+
match self {
95+
Item::Empty(_) => left,
96+
Item::Node(node) => node.cache(left, max_level, current_level),
97+
Item::Leaf(leaf) => leaf.cache(left),
98+
}
99+
}
100+
}

src/regex_radix_tree_new/leaf.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
use super::item::Item;
2+
use super::node::Node;
3+
use super::prefix::common_prefix;
4+
use super::regex::LazyRegex;
5+
use std::collections::HashMap;
6+
7+
#[derive(Debug)]
8+
pub struct Leaf<V> {
9+
pub(crate) values: HashMap<String, V>,
10+
pub(crate) regex: LazyRegex,
11+
}
12+
13+
impl<V> Leaf<V> {
14+
pub fn new(regex: &str, id: String, item: V, ignore_case: bool) -> Self {
15+
let mut values = HashMap::new();
16+
values.insert(id, item);
17+
18+
Leaf {
19+
values,
20+
regex: LazyRegex::new_leaf(regex, ignore_case),
21+
}
22+
}
23+
24+
/// Insert a new item into this node
25+
pub fn insert(mut self, regex: &str, id: String, item: V) -> Item<V> {
26+
if regex == self.regex.original.as_str() {
27+
self.values.insert(id, item);
28+
29+
return Item::Leaf(self);
30+
}
31+
32+
let prefix = common_prefix(self.regex.original.as_str(), regex);
33+
let mut leaf_values = HashMap::new();
34+
leaf_values.insert(id, item);
35+
36+
let leaf = Item::Leaf(Leaf {
37+
values: leaf_values,
38+
regex: LazyRegex::new_leaf(regex, self.regex.ignore_case),
39+
});
40+
41+
Item::Node(Node {
42+
regex: LazyRegex::new_node(prefix, self.regex.ignore_case),
43+
children: vec![Item::Leaf(self), leaf],
44+
})
45+
}
46+
47+
/// Find values associated to this haystack
48+
pub fn find(&self, haystack: &str) -> Vec<&V> {
49+
if self.regex.is_match(haystack) {
50+
return self.values.values().collect();
51+
}
52+
53+
Vec::new()
54+
}
55+
56+
pub fn get(&self, regex: &str) -> Vec<&V> {
57+
if self.regex.original.as_str() == regex {
58+
return self.values.values().collect();
59+
}
60+
61+
Vec::new()
62+
}
63+
64+
pub fn get_mut(&mut self, regex: &str) -> Vec<&mut V> {
65+
if self.regex.original.as_str() == regex {
66+
return self.values.values_mut().collect();
67+
}
68+
69+
Vec::new()
70+
}
71+
72+
/// Remove an item on this tree
73+
///
74+
/// This method returns true if there is no more data so it can be cleaned up
75+
pub fn remove(mut self, id: &str) -> (Item<V>, Option<V>) {
76+
let removed = self.values.remove(id);
77+
78+
match removed {
79+
None => (Item::Leaf(self), None),
80+
Some(value) => {
81+
if self.values.is_empty() {
82+
(Item::Empty(self.regex.ignore_case), Some(value))
83+
} else {
84+
(Item::Leaf(self), Some(value))
85+
}
86+
}
87+
}
88+
}
89+
90+
/// Length of node
91+
pub fn len(&self) -> usize {
92+
self.values.len()
93+
}
94+
95+
pub fn regex(&self) -> &str {
96+
self.regex.original.as_str()
97+
}
98+
99+
/// Cache current regex according to a limit and a level
100+
///
101+
/// This method must return new limit of element cached (passed limit minus number of element cached)
102+
/// which allow other node to avoid caching extra node
103+
///
104+
/// Implementation must not cache item if limit is equal to 0
105+
/// Implementation must not cache item if not caching on the current node level
106+
///
107+
/// Level argument allow to build cache on first level of the tree by priority
108+
/// Implementation must retain at which level this node is build and not do any caching
109+
/// if we are not on the current level
110+
pub fn cache(&mut self, left: u64) -> u64 {
111+
// Already cached
112+
if self.regex.compiled.is_some() {
113+
return left;
114+
}
115+
116+
self.regex.compile();
117+
118+
if self.regex.compiled.is_some() {
119+
return left - 1;
120+
}
121+
122+
left
123+
}
124+
}

src/regex_radix_tree_new/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
mod item;
2+
mod leaf;
3+
mod node;
4+
mod prefix;
5+
mod regex;
6+
mod trace;
7+
mod tree;
8+
9+
pub use tree::{RegexTreeMap, UniqueRegexTreeMap};

0 commit comments

Comments
 (0)