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, _: std::time::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(name.to_fqdn(), value.into(), valid_until);
221 self
222 }
223
224 pub fn txt_add(
225 &self,
226 name: impl ToFqdn,
227 value: impl Into<Txt>,
228 valid_until: std::time::Instant,
229 ) {
230 self.txt.insert(name.to_fqdn(), value.into(), valid_until);
231 }
232
233 pub fn ipv4_add(
234 &self,
235 name: impl ToFqdn,
236 value: Vec<Ipv4Addr>,
237 valid_until: std::time::Instant,
238 ) {
239 self.ipv4.insert(
240 name.to_fqdn(),
241 RecordSet {
242 rrset: Arc::from(value.into_boxed_slice()),
243 dnssec_status: DnssecStatus::Indeterminate,
244 },
245 valid_until,
246 );
247 }
248
249 pub fn ipv6_add(
250 &self,
251 name: impl ToFqdn,
252 value: Vec<Ipv6Addr>,
253 valid_until: std::time::Instant,
254 ) {
255 self.ipv6.insert(
256 name.to_fqdn(),
257 RecordSet {
258 rrset: Arc::from(value.into_boxed_slice()),
259 dnssec_status: DnssecStatus::Indeterminate,
260 },
261 valid_until,
262 );
263 }
264
265 pub fn ptr_add(&self, name: IpAddr, value: Vec<Box<str>>, valid_until: std::time::Instant) {
266 self.ptr.insert(
267 name,
268 RecordSet {
269 rrset: Arc::from(value.into_boxed_slice()),
270 dnssec_status: DnssecStatus::Indeterminate,
271 },
272 valid_until,
273 );
274 }
275
276 pub fn mx_add(&self, name: impl ToFqdn, value: Vec<MX>, valid_until: std::time::Instant) {
277 self.mx.insert(
278 name.to_fqdn(),
279 RecordSet {
280 rrset: Arc::from(value.into_boxed_slice()),
281 dnssec_status: DnssecStatus::Indeterminate,
282 },
283 valid_until,
284 );
285 }
286
287 #[allow(clippy::type_complexity)]
288 pub fn parameters<T>(
289 &self,
290 param: T,
291 ) -> Parameters<
292 '_,
293 T,
294 DummyCache<Box<str>, Txt>,
295 DummyCache<Box<str>, RecordSet<MX>>,
296 DummyCache<Box<str>, RecordSet<Ipv4Addr>>,
297 DummyCache<Box<str>, RecordSet<Ipv6Addr>>,
298 DummyCache<IpAddr, RecordSet<Box<str>>>,
299 > {
300 Parameters::new(param)
301 .with_txt_cache(&self.txt)
302 .with_mx_cache(&self.mx)
303 .with_ptr_cache(&self.ptr)
304 .with_ipv4_cache(&self.ipv4)
305 .with_ipv6_cache(&self.ipv6)
306 }
307 }
308}