1use std::collections::HashMap;
2use std::net::IpAddr;
3use std::num::NonZeroUsize;
4
5use lru::LruCache;
6use wp_model_core::model::{DataField, FValueStr, Value};
7
8#[derive(Debug, Clone)]
9pub struct FieldQueryCache {
10 str_idx: HashMap<FValueStr, usize>,
11 i64_idx: HashMap<i64, usize>,
12 ip_idx: HashMap<IpAddr, usize>,
13 cache_data: LruCache<EnumSizeIndex, Vec<DataField>>,
14 idx_num: usize,
15}
16
17impl Default for FieldQueryCache {
18 fn default() -> Self {
19 Self::with_capacity(100)
20 }
21}
22
23impl FieldQueryCache {
24 pub fn with_capacity(size: usize) -> Self {
25 let size = size.max(1);
26 Self {
27 str_idx: HashMap::new(),
28 i64_idx: HashMap::new(),
29 ip_idx: HashMap::new(),
30 cache_data: LruCache::new(NonZeroUsize::new(size).expect("non-zero cache size")),
31 idx_num: 0,
32 }
33 }
34
35 fn get_idx(&self, param: &DataField) -> Option<usize> {
36 match param.get_value() {
37 Value::Chars(v) => self.str_idx.get(v).copied(),
38 Value::Digit(v) => self.i64_idx.get(v).copied(),
39 Value::IpAddr(v) => self.ip_idx.get(v).copied(),
40 _ => None,
41 }
42 }
43
44 fn try_up_idx(&mut self, param: &DataField) -> Option<usize> {
45 match param.get_value() {
46 Value::Chars(v) => {
47 if let Some(idx) = self.str_idx.get(v) {
48 Some(*idx)
49 } else {
50 self.idx_num += 1;
51 self.str_idx.insert(v.clone(), self.idx_num);
52 Some(self.idx_num)
53 }
54 }
55 Value::Digit(v) => {
56 if let Some(idx) = self.i64_idx.get(v) {
57 Some(*idx)
58 } else {
59 self.idx_num += 1;
60 self.i64_idx.insert(*v, self.idx_num);
61 Some(self.idx_num)
62 }
63 }
64 Value::IpAddr(v) => {
65 if let Some(idx) = self.ip_idx.get(v) {
66 Some(*idx)
67 } else {
68 self.idx_num += 1;
69 self.ip_idx.insert(*v, self.idx_num);
70 Some(self.idx_num)
71 }
72 }
73 _ => None,
74 }
75 }
76}
77
78#[derive(PartialEq, Eq, Hash, Debug, Clone)]
79pub enum EnumSizeIndex {
80 Idx1(usize),
81 Idx2(usize, usize),
82 Idx3(usize, usize, usize),
83 Idx4(usize, usize, usize, usize),
84 Idx5(usize, usize, usize, usize, usize),
85 Idx6(usize, usize, usize, usize, usize, usize),
86}
87
88pub trait CacheAble<P, T, const N: usize> {
89 fn save(&mut self, params: &[P; N], result: T);
90 fn fetch(&self, params: &[P; N]) -> Option<&T>;
91}
92
93impl CacheAble<DataField, Vec<DataField>, 1> for FieldQueryCache {
94 fn save(&mut self, params: &[DataField; 1], result: Vec<DataField>) {
95 if let Some(i0) = self.try_up_idx(¶ms[0]) {
96 let idxs = EnumSizeIndex::Idx1(i0);
97 self.cache_data.put(idxs, result);
98 }
99 }
100
101 fn fetch(&self, params: &[DataField; 1]) -> Option<&Vec<DataField>> {
102 if let Some(i0) = self.get_idx(¶ms[0]) {
103 let idxs = EnumSizeIndex::Idx1(i0);
104 return self.cache_data.peek(&idxs);
105 }
106 None
107 }
108}
109
110impl CacheAble<DataField, Vec<DataField>, 2> for FieldQueryCache {
111 fn save(&mut self, params: &[DataField; 2], result: Vec<DataField>) {
112 if let (Some(i0), Some(i1)) = (self.try_up_idx(¶ms[0]), self.try_up_idx(¶ms[1])) {
113 let idxs = EnumSizeIndex::Idx2(i0, i1);
114 self.cache_data.put(idxs, result);
115 }
116 }
117
118 fn fetch(&self, params: &[DataField; 2]) -> Option<&Vec<DataField>> {
119 if let (Some(i0), Some(i1)) = (self.get_idx(¶ms[0]), self.get_idx(¶ms[1])) {
120 let idxs = EnumSizeIndex::Idx2(i0, i1);
121 return self.cache_data.peek(&idxs);
122 }
123 None
124 }
125}
126
127impl CacheAble<DataField, Vec<DataField>, 3> for FieldQueryCache {
128 fn save(&mut self, params: &[DataField; 3], result: Vec<DataField>) {
129 if let (Some(i0), Some(i1), Some(i2)) = (
130 self.try_up_idx(¶ms[0]),
131 self.try_up_idx(¶ms[1]),
132 self.try_up_idx(¶ms[2]),
133 ) {
134 let idxs = EnumSizeIndex::Idx3(i0, i1, i2);
135 self.cache_data.put(idxs, result);
136 }
137 }
138
139 fn fetch(&self, params: &[DataField; 3]) -> Option<&Vec<DataField>> {
140 if let (Some(i0), Some(i1), Some(i2)) = (
141 self.get_idx(¶ms[0]),
142 self.get_idx(¶ms[1]),
143 self.get_idx(¶ms[2]),
144 ) {
145 let idxs = EnumSizeIndex::Idx3(i0, i1, i2);
146 return self.cache_data.peek(&idxs);
147 }
148 None
149 }
150}
151
152impl CacheAble<DataField, Vec<DataField>, 4> for FieldQueryCache {
153 fn save(&mut self, params: &[DataField; 4], result: Vec<DataField>) {
154 if let (Some(i0), Some(i1), Some(i2), Some(i3)) = (
155 self.try_up_idx(¶ms[0]),
156 self.try_up_idx(¶ms[1]),
157 self.try_up_idx(¶ms[2]),
158 self.try_up_idx(¶ms[3]),
159 ) {
160 let idxs = EnumSizeIndex::Idx4(i0, i1, i2, i3);
161 self.cache_data.put(idxs, result);
162 }
163 }
164
165 fn fetch(&self, params: &[DataField; 4]) -> Option<&Vec<DataField>> {
166 if let (Some(i0), Some(i1), Some(i2), Some(i3)) = (
167 self.get_idx(¶ms[0]),
168 self.get_idx(¶ms[1]),
169 self.get_idx(¶ms[2]),
170 self.get_idx(¶ms[3]),
171 ) {
172 let idxs = EnumSizeIndex::Idx4(i0, i1, i2, i3);
173 return self.cache_data.peek(&idxs);
174 }
175 None
176 }
177}
178
179impl CacheAble<DataField, Vec<DataField>, 5> for FieldQueryCache {
180 fn save(&mut self, params: &[DataField; 5], result: Vec<DataField>) {
181 if let (Some(i0), Some(i1), Some(i2), Some(i3), Some(i4)) = (
182 self.try_up_idx(¶ms[0]),
183 self.try_up_idx(¶ms[1]),
184 self.try_up_idx(¶ms[2]),
185 self.try_up_idx(¶ms[3]),
186 self.try_up_idx(¶ms[4]),
187 ) {
188 let idxs = EnumSizeIndex::Idx5(i0, i1, i2, i3, i4);
189 self.cache_data.put(idxs, result);
190 }
191 }
192
193 fn fetch(&self, params: &[DataField; 5]) -> Option<&Vec<DataField>> {
194 if let (Some(i0), Some(i1), Some(i2), Some(i3), Some(i4)) = (
195 self.get_idx(¶ms[0]),
196 self.get_idx(¶ms[1]),
197 self.get_idx(¶ms[2]),
198 self.get_idx(¶ms[3]),
199 self.get_idx(¶ms[4]),
200 ) {
201 let idxs = EnumSizeIndex::Idx5(i0, i1, i2, i3, i4);
202 return self.cache_data.peek(&idxs);
203 }
204 None
205 }
206}
207
208impl CacheAble<DataField, Vec<DataField>, 6> for FieldQueryCache {
209 fn save(&mut self, params: &[DataField; 6], result: Vec<DataField>) {
210 if let (Some(i0), Some(i1), Some(i2), Some(i3), Some(i4), Some(i5)) = (
211 self.try_up_idx(¶ms[0]),
212 self.try_up_idx(¶ms[1]),
213 self.try_up_idx(¶ms[2]),
214 self.try_up_idx(¶ms[3]),
215 self.try_up_idx(¶ms[4]),
216 self.try_up_idx(¶ms[5]),
217 ) {
218 let idxs = EnumSizeIndex::Idx6(i0, i1, i2, i3, i4, i5);
219 self.cache_data.put(idxs, result);
220 }
221 }
222
223 fn fetch(&self, params: &[DataField; 6]) -> Option<&Vec<DataField>> {
224 if let (Some(i0), Some(i1), Some(i2), Some(i3), Some(i4), Some(i5)) = (
225 self.get_idx(¶ms[0]),
226 self.get_idx(¶ms[1]),
227 self.get_idx(¶ms[2]),
228 self.get_idx(¶ms[3]),
229 self.get_idx(¶ms[4]),
230 self.get_idx(¶ms[5]),
231 ) {
232 let idxs = EnumSizeIndex::Idx6(i0, i1, i2, i3, i4, i5);
233 return self.cache_data.peek(&idxs);
234 }
235 None
236 }
237}