ndn_store/
strategy_table.rs1use std::sync::Arc;
2
3use ndn_packet::Name;
4
5use crate::NameTrie;
6
7pub struct StrategyTable<S: Send + Sync + 'static + ?Sized>(NameTrie<Arc<S>>);
14
15impl<S: Send + Sync + 'static + ?Sized> StrategyTable<S> {
16 pub fn new() -> Self {
17 Self(NameTrie::new())
18 }
19
20 pub fn lpm(&self, name: &Name) -> Option<Arc<S>> {
22 self.0.lpm(name)
23 }
24
25 pub fn insert(&self, prefix: &Name, strategy: Arc<S>) {
27 self.0.insert(prefix, strategy);
28 }
29
30 pub fn remove(&self, prefix: &Name) {
32 self.0.remove(prefix);
33 }
34
35 pub fn dump(&self) -> Vec<(Name, Arc<S>)> {
37 self.0.dump()
38 }
39}
40
41impl<S: Send + Sync + 'static + ?Sized> Default for StrategyTable<S> {
42 fn default() -> Self {
43 Self::new()
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50 use bytes::Bytes;
51 use ndn_packet::NameComponent;
52
53 fn name(components: &[&str]) -> Name {
54 Name::from_components(
55 components
56 .iter()
57 .map(|s| NameComponent::generic(Bytes::copy_from_slice(s.as_bytes()))),
58 )
59 }
60
61 struct MockStrategy(u32);
63
64 #[test]
65 fn lpm_empty_returns_none() {
66 let table: StrategyTable<MockStrategy> = StrategyTable::new();
67 assert!(table.lpm(&name(&["a", "b"])).is_none());
68 }
69
70 #[test]
71 fn lpm_exact_match() {
72 let table: StrategyTable<MockStrategy> = StrategyTable::new();
73 table.insert(&name(&["a"]), Arc::new(MockStrategy(1)));
74 let s = table.lpm(&name(&["a"])).unwrap();
75 assert_eq!(s.0, 1);
76 }
77
78 #[test]
79 fn lpm_most_specific_wins() {
80 let table: StrategyTable<MockStrategy> = StrategyTable::new();
81 table.insert(&name(&["a"]), Arc::new(MockStrategy(10)));
82 table.insert(&name(&["a", "b"]), Arc::new(MockStrategy(20)));
83 let s = table.lpm(&name(&["a", "b", "c"])).unwrap();
84 assert_eq!(s.0, 20);
85 }
86
87 #[test]
88 fn lpm_fallback_to_shorter_prefix() {
89 let table: StrategyTable<MockStrategy> = StrategyTable::new();
90 table.insert(&name(&["a"]), Arc::new(MockStrategy(5)));
91 let s = table.lpm(&name(&["a", "b"])).unwrap();
92 assert_eq!(s.0, 5);
93 }
94
95 #[test]
96 fn lpm_default_strategy_at_root() {
97 let table: StrategyTable<MockStrategy> = StrategyTable::new();
98 table.insert(&Name::root(), Arc::new(MockStrategy(99)));
99 let s = table.lpm(&name(&["x", "y", "z"])).unwrap();
100 assert_eq!(s.0, 99);
101 }
102
103 #[test]
104 fn remove_clears_entry() {
105 let table: StrategyTable<MockStrategy> = StrategyTable::new();
106 table.insert(&name(&["a"]), Arc::new(MockStrategy(1)));
107 table.remove(&name(&["a"]));
108 assert!(table.lpm(&name(&["a"])).is_none());
109 }
110
111 #[test]
112 fn insert_replaces_strategy() {
113 let table: StrategyTable<MockStrategy> = StrategyTable::new();
114 table.insert(&name(&["a"]), Arc::new(MockStrategy(1)));
115 table.insert(&name(&["a"]), Arc::new(MockStrategy(2)));
116 let s = table.lpm(&name(&["a"])).unwrap();
117 assert_eq!(s.0, 2);
118 }
119}