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