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<Box<str>, Txt>,
43 NoCache<Box<str>, Arc<[MX]>>,
44 NoCache<Box<str>, Arc<[Ipv4Addr]>>,
45 NoCache<Box<str>, Arc<[Ipv6Addr]>>,
46 NoCache<IpAddr, Arc<[Box<str>]>>,
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<Box<str>, Txt>,
64 MXX: ResolverCache<Box<str>, Arc<[MX]>>,
65 IPV4: ResolverCache<Box<str>, Arc<[Ipv4Addr]>>,
66 IPV6: ResolverCache<Box<str>, Arc<[Ipv6Addr]>>,
67 PTR: ResolverCache<IpAddr, Arc<[Box<str>]>>,
68{
69 pub fn with_txt_cache<NewTXT: ResolverCache<Box<str>, 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<Box<str>, Arc<[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<[Box<str>]>>>(
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<Box<str>, Arc<[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<Box<str>, Arc<[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::ToFqdn};
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>, Arc<[MX]>>,
198 pub ptr: DummyCache<IpAddr, Arc<[Box<str>]>>,
199 pub ipv4: DummyCache<Box<str>, Arc<[Ipv4Addr]>>,
200 pub ipv6: DummyCache<Box<str>, Arc<[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 Arc::from(value.into_boxed_slice()),
242 valid_until,
243 );
244 }
245
246 pub fn ipv6_add(
247 &self,
248 name: impl ToFqdn,
249 value: Vec<Ipv6Addr>,
250 valid_until: std::time::Instant,
251 ) {
252 self.ipv6.insert(
253 name.to_fqdn(),
254 Arc::from(value.into_boxed_slice()),
255 valid_until,
256 );
257 }
258
259 pub fn ptr_add(&self, name: IpAddr, value: Vec<Box<str>>, valid_until: std::time::Instant) {
260 self.ptr
261 .insert(name, Arc::from(value.into_boxed_slice()), valid_until);
262 }
263
264 pub fn mx_add(&self, name: impl ToFqdn, value: Vec<MX>, valid_until: std::time::Instant) {
265 self.mx.insert(
266 name.to_fqdn(),
267 Arc::from(value.into_boxed_slice()),
268 valid_until,
269 );
270 }
271
272 #[allow(clippy::type_complexity)]
273 pub fn parameters<T>(
274 &self,
275 param: T,
276 ) -> Parameters<
277 '_,
278 T,
279 DummyCache<Box<str>, Txt>,
280 DummyCache<Box<str>, Arc<[MX]>>,
281 DummyCache<Box<str>, Arc<[Ipv4Addr]>>,
282 DummyCache<Box<str>, Arc<[Ipv6Addr]>>,
283 DummyCache<IpAddr, Arc<[Box<str>]>>,
284 > {
285 Parameters::new(param)
286 .with_txt_cache(&self.txt)
287 .with_mx_cache(&self.mx)
288 .with_ptr_cache(&self.ptr)
289 .with_ipv4_cache(&self.ipv4)
290 .with_ipv6_cache(&self.ipv6)
291 }
292 }
293}