1use crate::{MX, Parameters, ResolverCache, Txt};
8use std::{
9 borrow::Borrow,
10 hash::Hash,
11 marker::PhantomData,
12 net::{IpAddr, Ipv4Addr, Ipv6Addr},
13 sync::Arc,
14};
15
16pub struct NoCache<K, V>(PhantomData<(K, V)>);
17
18impl<K, V> ResolverCache<K, V> for NoCache<K, V> {
19 fn get<Q>(&self, _: &Q) -> Option<V>
20 where
21 K: Borrow<Q>,
22 Q: Hash + Eq + ?Sized,
23 {
24 None
25 }
26
27 fn remove<Q>(&self, _: &Q) -> Option<V>
28 where
29 K: Borrow<Q>,
30 Q: Hash + Eq + ?Sized,
31 {
32 None
33 }
34
35 fn insert(&self, _: K, _: V, _: std::time::Instant) {}
36}
37
38impl<P>
39 Parameters<
40 '_,
41 P,
42 NoCache<String, Txt>,
43 NoCache<String, Arc<Vec<MX>>>,
44 NoCache<String, Arc<Vec<Ipv4Addr>>>,
45 NoCache<String, Arc<Vec<Ipv6Addr>>>,
46 NoCache<IpAddr, Arc<Vec<String>>>,
47 >
48{
49 pub fn new(params: P) -> Self {
50 Parameters {
51 params,
52 cache_txt: None,
53 cache_mx: None,
54 cache_ptr: None,
55 cache_ipv4: None,
56 cache_ipv6: None,
57 }
58 }
59}
60
61impl<'x, P, TXT, MXX, IPV4, IPV6, PTR> Parameters<'x, P, TXT, MXX, IPV4, IPV6, PTR>
62where
63 TXT: ResolverCache<String, Txt>,
64 MXX: ResolverCache<String, Arc<Vec<MX>>>,
65 IPV4: ResolverCache<String, Arc<Vec<Ipv4Addr>>>,
66 IPV6: ResolverCache<String, Arc<Vec<Ipv6Addr>>>,
67 PTR: ResolverCache<IpAddr, Arc<Vec<String>>>,
68{
69 pub fn with_txt_cache<NewTXT: ResolverCache<String, Txt>>(
70 self,
71 cache: &'x NewTXT,
72 ) -> Parameters<'x, P, NewTXT, MXX, IPV4, IPV6, PTR> {
73 Parameters {
74 params: self.params,
75 cache_txt: Some(cache),
76 cache_mx: self.cache_mx,
77 cache_ptr: self.cache_ptr,
78 cache_ipv4: self.cache_ipv4,
79 cache_ipv6: self.cache_ipv6,
80 }
81 }
82
83 pub fn with_mx_cache<NewMX: ResolverCache<String, Arc<Vec<MX>>>>(
84 self,
85 cache: &'x NewMX,
86 ) -> Parameters<'x, P, TXT, NewMX, IPV4, IPV6, PTR> {
87 Parameters {
88 params: self.params,
89 cache_txt: self.cache_txt,
90 cache_mx: Some(cache),
91 cache_ptr: self.cache_ptr,
92 cache_ipv4: self.cache_ipv4,
93 cache_ipv6: self.cache_ipv6,
94 }
95 }
96
97 pub fn with_ptr_cache<NewPTR: ResolverCache<IpAddr, Arc<Vec<String>>>>(
98 self,
99 cache: &'x NewPTR,
100 ) -> Parameters<'x, P, TXT, MXX, IPV4, IPV6, NewPTR> {
101 Parameters {
102 params: self.params,
103 cache_txt: self.cache_txt,
104 cache_mx: self.cache_mx,
105 cache_ptr: Some(cache),
106 cache_ipv4: self.cache_ipv4,
107 cache_ipv6: self.cache_ipv6,
108 }
109 }
110
111 pub fn with_ipv4_cache<NewIPV4: ResolverCache<String, Arc<Vec<Ipv4Addr>>>>(
112 self,
113 cache: &'x NewIPV4,
114 ) -> Parameters<'x, P, TXT, MXX, NewIPV4, IPV6, PTR> {
115 Parameters {
116 params: self.params,
117 cache_txt: self.cache_txt,
118 cache_mx: self.cache_mx,
119 cache_ptr: self.cache_ptr,
120 cache_ipv4: Some(cache),
121 cache_ipv6: self.cache_ipv6,
122 }
123 }
124
125 pub fn with_ipv6_cache<NewIPV6: ResolverCache<String, Arc<Vec<Ipv6Addr>>>>(
126 self,
127 cache: &'x NewIPV6,
128 ) -> Parameters<'x, P, TXT, MXX, IPV4, NewIPV6, PTR> {
129 Parameters {
130 params: self.params,
131 cache_txt: self.cache_txt,
132 cache_mx: self.cache_mx,
133 cache_ptr: self.cache_ptr,
134 cache_ipv4: self.cache_ipv4,
135 cache_ipv6: Some(cache),
136 }
137 }
138
139 pub fn clone_with<NewP>(
140 &self,
141 params: NewP,
142 ) -> Parameters<'x, NewP, TXT, MXX, IPV4, IPV6, PTR> {
143 Parameters {
144 params,
145 cache_txt: self.cache_txt,
146 cache_mx: self.cache_mx,
147 cache_ptr: self.cache_ptr,
148 cache_ipv4: self.cache_ipv4,
149 cache_ipv6: self.cache_ipv6,
150 }
151 }
152}
153
154#[cfg(test)]
155pub mod test {
156 use std::{
157 borrow::Borrow,
158 hash::Hash,
159 net::{IpAddr, Ipv4Addr, Ipv6Addr},
160 sync::Arc,
161 };
162
163 use crate::{MX, Parameters, ResolverCache, Txt, common::resolver::IntoFqdn};
164
165 pub(crate) struct DummyCache<K, V>(std::sync::Mutex<std::collections::HashMap<K, V>>);
166
167 impl<K: Hash + Eq, V: Clone> DummyCache<K, V> {
168 pub fn new() -> Self {
169 DummyCache(std::sync::Mutex::new(std::collections::HashMap::new()))
170 }
171 }
172
173 impl<K: Hash + Eq, V: Clone> ResolverCache<K, V> for DummyCache<K, V> {
174 fn get<Q>(&self, key: &Q) -> Option<V>
175 where
176 K: Borrow<Q>,
177 Q: Hash + Eq + ?Sized,
178 {
179 self.0.lock().unwrap().get(key).cloned()
180 }
181
182 fn remove<Q>(&self, key: &Q) -> Option<V>
183 where
184 K: Borrow<Q>,
185 Q: Hash + Eq + ?Sized,
186 {
187 self.0.lock().unwrap().remove(key)
188 }
189
190 fn insert(&self, key: K, value: V, _: std::time::Instant) {
191 self.0.lock().unwrap().insert(key, value);
192 }
193 }
194
195 pub(crate) struct DummyCaches {
196 pub txt: DummyCache<String, Txt>,
197 pub mx: DummyCache<String, Arc<Vec<MX>>>,
198 pub ptr: DummyCache<IpAddr, Arc<Vec<String>>>,
199 pub ipv4: DummyCache<String, Arc<Vec<Ipv4Addr>>>,
200 pub ipv6: DummyCache<String, Arc<Vec<Ipv6Addr>>>,
201 }
202
203 impl DummyCaches {
204 pub fn new() -> Self {
205 Self {
206 txt: DummyCache::new(),
207 mx: DummyCache::new(),
208 ptr: DummyCache::new(),
209 ipv4: DummyCache::new(),
210 ipv6: DummyCache::new(),
211 }
212 }
213
214 pub fn with_txt<'x>(
215 self,
216 name: impl IntoFqdn<'x>,
217 value: impl Into<Txt>,
218 valid_until: std::time::Instant,
219 ) -> Self {
220 self.txt
221 .insert(name.into_fqdn().into_owned(), value.into(), valid_until);
222 self
223 }
224
225 pub fn txt_add<'x>(
226 &self,
227 name: impl IntoFqdn<'x>,
228 value: impl Into<Txt>,
229 valid_until: std::time::Instant,
230 ) {
231 self.txt
232 .insert(name.into_fqdn().into_owned(), value.into(), valid_until);
233 }
234
235 pub fn ipv4_add<'x>(
236 &self,
237 name: impl IntoFqdn<'x>,
238 value: Vec<Ipv4Addr>,
239 valid_until: std::time::Instant,
240 ) {
241 self.ipv4
242 .insert(name.into_fqdn().into_owned(), Arc::new(value), valid_until);
243 }
244
245 pub fn ipv6_add<'x>(
246 &self,
247 name: impl IntoFqdn<'x>,
248 value: Vec<Ipv6Addr>,
249 valid_until: std::time::Instant,
250 ) {
251 self.ipv6
252 .insert(name.into_fqdn().into_owned(), Arc::new(value), valid_until);
253 }
254
255 pub fn ptr_add(&self, name: IpAddr, value: Vec<String>, valid_until: std::time::Instant) {
256 self.ptr.insert(name, Arc::new(value), valid_until);
257 }
258
259 pub fn mx_add<'x>(
260 &self,
261 name: impl IntoFqdn<'x>,
262 value: Vec<MX>,
263 valid_until: std::time::Instant,
264 ) {
265 self.mx
266 .insert(name.into_fqdn().into_owned(), Arc::new(value), valid_until);
267 }
268
269 #[allow(clippy::type_complexity)]
270 pub fn parameters<T>(
271 &self,
272 param: T,
273 ) -> Parameters<
274 '_,
275 T,
276 DummyCache<String, Txt>,
277 DummyCache<String, Arc<Vec<MX>>>,
278 DummyCache<String, Arc<Vec<Ipv4Addr>>>,
279 DummyCache<String, Arc<Vec<Ipv6Addr>>>,
280 DummyCache<IpAddr, Arc<Vec<String>>>,
281 > {
282 Parameters::new(param)
283 .with_txt_cache(&self.txt)
284 .with_mx_cache(&self.mx)
285 .with_ptr_cache(&self.ptr)
286 .with_ipv4_cache(&self.ipv4)
287 .with_ipv6_cache(&self.ipv6)
288 }
289 }
290}