1use crate::{MX, Parameters, RecordSet, ResolverCache, Txt};
8use std::{
9 borrow::Borrow,
10 hash::Hash,
11 marker::PhantomData,
12 net::{IpAddr, Ipv4Addr, Ipv6Addr},
13};
14
15pub struct NoCache<K, V>(PhantomData<(K, V)>);
16
17impl<K, V> ResolverCache<K, V> for NoCache<K, V> {
18 fn get<Q>(&self, _: &Q) -> Option<V>
19 where
20 K: Borrow<Q>,
21 Q: Hash + Eq + ?Sized,
22 {
23 None
24 }
25
26 fn remove<Q>(&self, _: &Q) -> Option<V>
27 where
28 K: Borrow<Q>,
29 Q: Hash + Eq + ?Sized,
30 {
31 None
32 }
33
34 fn insert(&self, _: K, _: V, _: crate::Instant) {}
35}
36
37impl<P>
38 Parameters<
39 '_,
40 P,
41 NoCache<Box<str>, Txt>,
42 NoCache<Box<str>, RecordSet<MX>>,
43 NoCache<Box<str>, RecordSet<Ipv4Addr>>,
44 NoCache<Box<str>, RecordSet<Ipv6Addr>>,
45 NoCache<IpAddr, RecordSet<Box<str>>>,
46 >
47{
48 pub fn new(params: P) -> Self {
49 Parameters {
50 params,
51 cache_txt: None,
52 cache_mx: None,
53 cache_ptr: None,
54 cache_ipv4: None,
55 cache_ipv6: None,
56 }
57 }
58}
59
60impl<'x, P, TXT, MXX, IPV4, IPV6, PTR> Parameters<'x, P, TXT, MXX, IPV4, IPV6, PTR>
61where
62 TXT: ResolverCache<Box<str>, Txt>,
63 MXX: ResolverCache<Box<str>, RecordSet<MX>>,
64 IPV4: ResolverCache<Box<str>, RecordSet<Ipv4Addr>>,
65 IPV6: ResolverCache<Box<str>, RecordSet<Ipv6Addr>>,
66 PTR: ResolverCache<IpAddr, RecordSet<Box<str>>>,
67{
68 pub fn with_txt_cache<NewTXT: ResolverCache<Box<str>, Txt>>(
69 self,
70 cache: &'x NewTXT,
71 ) -> Parameters<'x, P, NewTXT, MXX, IPV4, IPV6, PTR> {
72 Parameters {
73 params: self.params,
74 cache_txt: Some(cache),
75 cache_mx: self.cache_mx,
76 cache_ptr: self.cache_ptr,
77 cache_ipv4: self.cache_ipv4,
78 cache_ipv6: self.cache_ipv6,
79 }
80 }
81
82 pub fn with_mx_cache<NewMX: ResolverCache<Box<str>, RecordSet<MX>>>(
83 self,
84 cache: &'x NewMX,
85 ) -> Parameters<'x, P, TXT, NewMX, IPV4, IPV6, PTR> {
86 Parameters {
87 params: self.params,
88 cache_txt: self.cache_txt,
89 cache_mx: Some(cache),
90 cache_ptr: self.cache_ptr,
91 cache_ipv4: self.cache_ipv4,
92 cache_ipv6: self.cache_ipv6,
93 }
94 }
95
96 pub fn with_ptr_cache<NewPTR: ResolverCache<IpAddr, RecordSet<Box<str>>>>(
97 self,
98 cache: &'x NewPTR,
99 ) -> Parameters<'x, P, TXT, MXX, IPV4, IPV6, NewPTR> {
100 Parameters {
101 params: self.params,
102 cache_txt: self.cache_txt,
103 cache_mx: self.cache_mx,
104 cache_ptr: Some(cache),
105 cache_ipv4: self.cache_ipv4,
106 cache_ipv6: self.cache_ipv6,
107 }
108 }
109
110 pub fn with_ipv4_cache<NewIPV4: ResolverCache<Box<str>, RecordSet<Ipv4Addr>>>(
111 self,
112 cache: &'x NewIPV4,
113 ) -> Parameters<'x, P, TXT, MXX, NewIPV4, IPV6, PTR> {
114 Parameters {
115 params: self.params,
116 cache_txt: self.cache_txt,
117 cache_mx: self.cache_mx,
118 cache_ptr: self.cache_ptr,
119 cache_ipv4: Some(cache),
120 cache_ipv6: self.cache_ipv6,
121 }
122 }
123
124 pub fn with_ipv6_cache<NewIPV6: ResolverCache<Box<str>, RecordSet<Ipv6Addr>>>(
125 self,
126 cache: &'x NewIPV6,
127 ) -> Parameters<'x, P, TXT, MXX, IPV4, NewIPV6, PTR> {
128 Parameters {
129 params: self.params,
130 cache_txt: self.cache_txt,
131 cache_mx: self.cache_mx,
132 cache_ptr: self.cache_ptr,
133 cache_ipv4: self.cache_ipv4,
134 cache_ipv6: Some(cache),
135 }
136 }
137
138 pub fn clone_with<NewP>(
139 &self,
140 params: NewP,
141 ) -> Parameters<'x, NewP, TXT, MXX, IPV4, IPV6, PTR> {
142 Parameters {
143 params,
144 cache_txt: self.cache_txt,
145 cache_mx: self.cache_mx,
146 cache_ptr: self.cache_ptr,
147 cache_ipv4: self.cache_ipv4,
148 cache_ipv6: self.cache_ipv6,
149 }
150 }
151}
152
153#[cfg(test)]
154pub mod test {
155 use crate::{
156 DnssecStatus, MX, Parameters, RecordSet, ResolverCache, Txt, common::resolver::ToFqdn,
157 };
158 use std::{
159 borrow::Borrow,
160 hash::Hash,
161 net::{IpAddr, Ipv4Addr, Ipv6Addr},
162 sync::Arc,
163 };
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<Box<str>, Txt>,
197 pub mx: DummyCache<Box<str>, RecordSet<MX>>,
198 pub ptr: DummyCache<IpAddr, RecordSet<Box<str>>>,
199 pub ipv4: DummyCache<Box<str>, RecordSet<Ipv4Addr>>,
200 pub ipv6: DummyCache<Box<str>, RecordSet<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(
215 self,
216 name: impl ToFqdn,
217 value: impl Into<Txt>,
218 valid_until: std::time::Instant,
219 ) -> Self {
220 self.txt.insert(
221 name.to_fqdn().into_owned().into_boxed_str(),
222 value.into(),
223 valid_until,
224 );
225 self
226 }
227
228 pub fn txt_add(
229 &self,
230 name: impl ToFqdn,
231 value: impl Into<Txt>,
232 valid_until: std::time::Instant,
233 ) {
234 self.txt.insert(
235 name.to_fqdn().into_owned().into_boxed_str(),
236 value.into(),
237 valid_until,
238 );
239 }
240
241 pub fn ipv4_add(
242 &self,
243 name: impl ToFqdn,
244 value: Vec<Ipv4Addr>,
245 valid_until: std::time::Instant,
246 ) {
247 self.ipv4.insert(
248 name.to_fqdn().into_owned().into_boxed_str(),
249 RecordSet {
250 rrset: Arc::from(value.into_boxed_slice()),
251 dnssec_status: DnssecStatus::Indeterminate,
252 },
253 valid_until,
254 );
255 }
256
257 pub fn ipv6_add(
258 &self,
259 name: impl ToFqdn,
260 value: Vec<Ipv6Addr>,
261 valid_until: std::time::Instant,
262 ) {
263 self.ipv6.insert(
264 name.to_fqdn().into_owned().into_boxed_str(),
265 RecordSet {
266 rrset: Arc::from(value.into_boxed_slice()),
267 dnssec_status: DnssecStatus::Indeterminate,
268 },
269 valid_until,
270 );
271 }
272
273 pub fn ptr_add(&self, name: IpAddr, value: Vec<Box<str>>, valid_until: std::time::Instant) {
274 self.ptr.insert(
275 name,
276 RecordSet {
277 rrset: Arc::from(value.into_boxed_slice()),
278 dnssec_status: DnssecStatus::Indeterminate,
279 },
280 valid_until,
281 );
282 }
283
284 pub fn mx_add(&self, name: impl ToFqdn, value: Vec<MX>, valid_until: std::time::Instant) {
285 self.mx.insert(
286 name.to_fqdn().into_owned().into_boxed_str(),
287 RecordSet {
288 rrset: Arc::from(value.into_boxed_slice()),
289 dnssec_status: DnssecStatus::Indeterminate,
290 },
291 valid_until,
292 );
293 }
294
295 #[allow(clippy::type_complexity)]
296 pub fn parameters<T>(
297 &self,
298 param: T,
299 ) -> Parameters<
300 '_,
301 T,
302 DummyCache<Box<str>, Txt>,
303 DummyCache<Box<str>, RecordSet<MX>>,
304 DummyCache<Box<str>, RecordSet<Ipv4Addr>>,
305 DummyCache<Box<str>, RecordSet<Ipv6Addr>>,
306 DummyCache<IpAddr, RecordSet<Box<str>>>,
307 > {
308 Parameters::new(param)
309 .with_txt_cache(&self.txt)
310 .with_mx_cache(&self.mx)
311 .with_ptr_cache(&self.ptr)
312 .with_ipv4_cache(&self.ipv4)
313 .with_ipv6_cache(&self.ipv6)
314 }
315 }
316}