links_domainmap/
map.rs

1//! A map with [domain name][Domain] keys, with support for wildcards
2
3use alloc::vec::{IntoIter as VecIter, Vec};
4use core::{
5	fmt::Debug,
6	hash::{Hash, Hasher},
7	mem,
8	slice::{Iter as SliceIter, IterMut as SliceIterMut},
9};
10
11use crate::Domain;
12
13/// A map with [domain name][Domain] keys, with support for wildcards
14///
15/// A [`DomainMap<T>`] holds "[presented identifiers]" (domain names possibly
16/// with wildcards) as [`Domain`]s. A [`DomainMap`] can be indexed using a
17/// [`Domain`], which stores either a "[reference identifier]" (for matching
18/// methods, e.g. `get` or `get_mut`) or a "[presented identifier]" (for
19/// equality-comparing methods, e.g. `get_eq` or `remove`).
20///
21/// Currently, this is implemented using an associative array, but this may
22/// change in the future.
23///
24/// # Examples
25///
26/// ```rust
27/// use links_domainmap::{Domain, DomainMap};
28///
29/// # use links_domainmap::ParseError;
30/// # fn main() -> Result<(), ParseError> {
31/// // Create a new `DomainMap` with `u32` values
32/// let mut domainmap = DomainMap::<u32>::new(); // or `with_capacity()`
33///
34/// // Set a value for `example.com`
35/// domainmap.set(Domain::presented("example.com")?, 5);
36///
37/// // Set a value for the wildcard domain `*.example.net`
38/// domainmap.set(Domain::presented("*.example.net")?, 100);
39///
40/// // Get the value for the domain matching `example.com`
41/// assert_eq!(domainmap.get(&Domain::reference("example.com")?), Some(&5));
42///
43/// // Get the value for the domain matching `foo.example.net`
44/// assert_eq!(
45/// 	domainmap.get(&Domain::reference("foo.example.net")?),
46/// 	Some(&100)
47/// );
48///
49/// // Get the value for the domain `*.example.net` (using `==` internally)
50/// assert_eq!(
51/// 	domainmap.get_eq(&Domain::presented("*.example.net")?),
52/// 	Some(&100)
53/// );
54///
55/// // Try to get the value for the domain matching `a.b.c.example.net`
56/// assert_eq!(
57/// 	domainmap.get(&Domain::reference("a.b.c.example.net")?),
58/// 	None // Wildcards only work for one label
59/// );
60///
61/// // Update the value for `example.com`
62/// let old_value = domainmap.set(Domain::presented("example.com")?, 50);
63/// assert_eq!(old_value, Some(5));
64///
65/// // Modify the value for the domain matching `foo.example.net`
66/// let val = domainmap.get_mut(&Domain::reference("foo.example.net")?);
67/// if let Some(val) = val {
68/// 	*val += 1;
69/// 	assert_eq!(val, &101);
70/// }
71///
72/// // Set a value for `www.example.net`, overriding the wildcard `*.example.net`
73/// domainmap.set(Domain::presented("www.example.net")?, 250);
74///
75/// // The wildcard still exists, but is overridden for `www.example.net`
76/// assert_eq!(
77/// 	domainmap.get(&Domain::reference("www.example.net")?),
78/// 	Some(&250)
79/// );
80/// assert_eq!(
81/// 	domainmap.get(&Domain::reference("other.example.net")?),
82/// 	Some(&101)
83/// );
84///
85/// // Remove the entry for `example.com`
86/// let old_value = domainmap.remove(&Domain::presented("example.com")?);
87/// assert_eq!(old_value, Some(50));
88/// assert_eq!(
89/// 	domainmap.get(&Domain::reference("example.com")?),
90/// 	None // Not in the map anymore
91/// );
92///
93/// // Show the amount of key-value pairs in the map
94/// assert_eq!(domainmap.len(), 2); // `*.example.net` and `www.example.net`
95///
96/// // Clear the map
97/// domainmap.clear();
98/// assert!(domainmap.is_empty());
99/// # Ok(())
100/// # }
101/// ```
102///
103/// [reference identifier]: https://www.rfc-editor.org/rfc/rfc6125#page-12
104/// [presented identifier]: https://www.rfc-editor.org/rfc/rfc6125#page-11
105#[derive(Debug, Clone)]
106pub struct DomainMap<T> {
107	data: Vec<(Domain, T)>,
108}
109
110impl<T> DomainMap<T> {
111	/// Create a new empty [`DomainMap`]
112	#[must_use]
113	pub const fn new() -> Self {
114		Self { data: Vec::new() }
115	}
116
117	/// Create a new empty [`DomainMap`] with enough capacity for at least `cap`
118	/// key-value pairs
119	#[must_use]
120	pub fn with_capacity(cap: usize) -> Self {
121		Self {
122			data: Vec::with_capacity(cap),
123		}
124	}
125
126	/// Set the value for the given domain, adding a new entry if the domain was
127	/// not already in the map, and returning the old value otherwise
128	///
129	/// # Examples
130	///
131	/// ```rust
132	/// # use links_domainmap::{DomainMap, Domain, ParseError};
133	/// # struct Certificate;
134	/// # fn get_certificate() -> Certificate { Certificate }
135	/// # fn main() -> Result<(), ParseError> {
136	/// let mut domainmap = DomainMap::<Certificate>::new();
137	///
138	/// domainmap.set(Domain::presented("example.com")?, get_certificate());
139	///
140	/// domainmap.set(Domain::presented("*.example.com")?, get_certificate());
141	///
142	/// assert!(domainmap.get(&Domain::presented("example.com")?).is_some());
143	/// # Ok(())
144	/// # }
145	/// ```
146	pub fn set(&mut self, domain: Domain, value: T) -> Option<T> {
147		for (k, v) in &mut self.data {
148			if *k == domain {
149				return Some(mem::replace(v, value));
150			}
151		}
152
153		self.data.push((domain, value));
154		None
155	}
156
157	/// Get the value matching the [reference identifier] domain
158	///
159	/// If there is a value for a wildcard domain matching the given domain, and
160	/// for the given domain itself, the specific (non-wildcard) domain's value
161	/// is always returned, regardless of insertion order
162	///
163	/// [reference identifier]: https://www.rfc-editor.org/rfc/rfc6125#page-12
164	///
165	/// # Examples
166	///
167	/// ```rust
168	/// # use links_domainmap::{DomainMap, Domain, ParseError};
169	/// # struct Certificate;
170	/// # fn get_certificate() -> Certificate { Certificate }
171	/// # fn main() -> Result<(), ParseError> {
172	/// let mut domainmap = DomainMap::<Certificate>::new();
173	///
174	/// domainmap.set(Domain::presented("*.example.com")?, get_certificate());
175	///
176	/// assert!(domainmap.get(&Domain::reference("example.com")?).is_none());
177	///
178	/// assert!(domainmap
179	/// 	.get(&Domain::reference("www.example.com")?)
180	/// 	.is_some());
181	/// # Ok(())
182	/// # }
183	/// ```
184	///
185	/// ```rust
186	/// # use links_domainmap::{DomainMap, Domain, ParseError};
187	/// # fn main() -> Result<(), ParseError> {
188	/// let mut domainmap = DomainMap::<u64>::new();
189	///
190	/// domainmap.set(Domain::presented("foo.example.com")?, 10);
191	/// domainmap.set(Domain::presented("*.example.com")?, 50);
192	///
193	/// assert_eq!(
194	/// 	domainmap.get(&Domain::reference("bar.example.com")?),
195	/// 	Some(&50)
196	/// );
197	///
198	/// assert_eq!(
199	/// 	domainmap.get(&Domain::reference("foo.example.com")?),
200	/// 	Some(&10)
201	/// );
202	/// # Ok(())
203	/// # }
204	/// ```
205	#[must_use]
206	pub fn get(&self, domain: &Domain) -> Option<&T> {
207		let mut wildcard_result = None;
208
209		for (k, v) in &self.data {
210			if domain.matches(k).unwrap_or(false) {
211				if k.is_wildcard() {
212					wildcard_result = Some(v);
213				} else {
214					return Some(v);
215				}
216			}
217		}
218
219		wildcard_result
220	}
221
222	/// Get a mutable reference to the value matching the [reference identifier]
223	///
224	/// If there is a value for a wildcard domain matching the given domain, and
225	/// for the given domain itself, the specific (non-wildcard) domain's value
226	/// is always returned, regardless of insertion order
227	///
228	/// [reference identifier]: https://www.rfc-editor.org/rfc/rfc6125#page-12
229	///
230	/// # Examples
231	///
232	/// ```rust
233	/// # use links_domainmap::{DomainMap, Domain, ParseError};
234	/// # struct Certificate;
235	/// # fn get_certificate() -> Certificate { Certificate }
236	/// # fn main() -> Result<(), ParseError> {
237	/// let mut domainmap = DomainMap::<Certificate>::new();
238	///
239	/// domainmap.set(Domain::presented("*.example.com")?, get_certificate());
240	///
241	/// assert!(domainmap
242	/// 	.get_mut(&Domain::reference("example.com")?)
243	/// 	.is_none());
244	///
245	/// assert!(domainmap
246	/// 	.get_mut(&Domain::reference("www.example.com")?)
247	/// 	.is_some());
248	/// # Ok(())
249	/// # }
250	/// ```
251	///
252	/// ```rust
253	/// # use links_domainmap::{DomainMap, Domain, ParseError};
254	/// # fn main() -> Result<(), ParseError> {
255	/// let mut domainmap = DomainMap::<u64>::new();
256	///
257	/// domainmap.set(Domain::presented("foo.example.com")?, 10);
258	/// domainmap.set(Domain::presented("*.example.com")?, 50);
259	///
260	/// assert_eq!(
261	/// 	domainmap.get_mut(&Domain::reference("bar.example.com")?),
262	/// 	Some(&mut 50)
263	/// );
264	///
265	/// assert_eq!(
266	/// 	domainmap.get_mut(&Domain::reference("foo.example.com")?),
267	/// 	Some(&mut 10)
268	/// );
269	/// # Ok(())
270	/// # }
271	/// ```
272	#[must_use]
273	pub fn get_mut(&mut self, domain: &Domain) -> Option<&mut T> {
274		let mut wildcard_result = None;
275
276		for (k, v) in &mut self.data {
277			if domain.matches(k).unwrap_or(false) {
278				if k.is_wildcard() {
279					wildcard_result = Some(v);
280				} else {
281					return Some(v);
282				}
283			}
284		}
285
286		wildcard_result
287	}
288
289	/// Get the value for the given domain, checking using `==` instead of
290	/// matching
291	///
292	/// # Examples
293	///
294	/// ```rust
295	/// # use links_domainmap::{DomainMap, Domain, ParseError};
296	/// # struct Certificate;
297	/// # fn get_certificate() -> Certificate { Certificate }
298	/// # fn main() -> Result<(), ParseError> {
299	/// let mut domainmap = DomainMap::<Certificate>::new();
300	///
301	/// domainmap.set(Domain::presented("*.example.com")?, get_certificate());
302	///
303	/// assert!(domainmap
304	/// 	.get_eq(&Domain::presented("www.example.com")?)
305	/// 	.is_none());
306	///
307	/// assert!(domainmap
308	/// 	.get_eq(&Domain::presented("*.example.com")?)
309	/// 	.is_some());
310	/// # Ok(())
311	/// # }
312	/// ```
313	#[must_use]
314	pub fn get_eq(&self, domain: &Domain) -> Option<&T> {
315		for (k, v) in &self.data {
316			if domain == k {
317				return Some(v);
318			}
319		}
320
321		None
322	}
323
324	/// Remove the given domain from the map, returning its value, if any
325	///
326	/// Note that unlike `DomainMap::get`, this method compares the domain using
327	/// `==` instead of checking for a match
328	///
329	/// # Examples
330	///
331	/// ```rust
332	/// # use links_domainmap::{DomainMap, Domain, ParseError};
333	/// # struct Certificate;
334	/// # fn get_certificate() -> Certificate { Certificate }
335	/// # fn main() -> Result<(), ParseError> {
336	/// let mut domainmap = DomainMap::<Certificate>::new();
337	///
338	/// domainmap.set(Domain::presented("*.example.com")?, get_certificate());
339	///
340	/// assert!(domainmap
341	/// 	.remove(&Domain::presented("example.com")?)
342	/// 	.is_none());
343	///
344	/// assert!(domainmap
345	/// 	.remove(&Domain::presented("*.example.com")?)
346	/// 	.is_some());
347	///
348	/// assert!(domainmap
349	/// 	.remove(&Domain::presented("*.example.com")?)
350	/// 	.is_none());
351	/// # Ok(())
352	/// # }
353	/// ```
354	pub fn remove(&mut self, domain: &Domain) -> Option<T> {
355		for (i, (k, _)) in self.data.iter_mut().enumerate() {
356			if k == domain {
357				let (_, v) = self.data.swap_remove(i);
358				return Some(v);
359			}
360		}
361
362		None
363	}
364
365	/// Clear the [`DomainMap`], removing all contents
366	///
367	/// # Examples
368	///
369	/// ```rust
370	/// # use links_domainmap::{DomainMap, Domain, ParseError};
371	/// # struct Certificate;
372	/// # fn get_certificate() -> Certificate { Certificate }
373	/// # fn main() -> Result<(), ParseError> {
374	/// let mut domainmap = DomainMap::<Certificate>::new();
375	///
376	/// domainmap.set(Domain::presented("example.com")?, get_certificate());
377	///
378	/// assert!(domainmap.get(&Domain::reference("example.com")?).is_some());
379	///
380	/// domainmap.clear();
381	///
382	/// assert!(domainmap.get(&Domain::reference("example.com")?).is_none());
383	/// # Ok(())
384	/// # }
385	/// ```
386	pub fn clear(&mut self) {
387		self.data.clear();
388	}
389
390	/// Get the number of key-value pairs in the [`DomainMap`]
391	///
392	/// # Examples
393	///
394	/// ```rust
395	/// # use links_domainmap::{DomainMap, Domain, ParseError};
396	/// # struct Certificate;
397	/// # fn get_certificate() -> Certificate { Certificate }
398	/// # fn main() -> Result<(), ParseError> {
399	/// let mut domainmap = DomainMap::<Certificate>::new();
400	///
401	/// assert_eq!(domainmap.len(), 0);
402	///
403	/// domainmap.set(Domain::presented("example.com")?, get_certificate());
404	///
405	/// assert_eq!(domainmap.len(), 1);
406	/// # Ok(())
407	/// # }
408	/// ```
409	#[must_use]
410	pub fn len(&self) -> usize {
411		self.data.len()
412	}
413
414	/// Check whether the [`DomainMap`] is empty, i.e. if its length is 0
415	///
416	/// # Examples
417	///
418	/// ```rust
419	/// # use links_domainmap::{DomainMap, Domain, ParseError};
420	/// # struct Certificate;
421	/// # fn get_certificate() -> Certificate { Certificate }
422	/// # fn main() -> Result<(), ParseError> {
423	/// let mut domainmap = DomainMap::<Certificate>::new();
424	///
425	/// assert!(domainmap.is_empty());
426	///
427	/// domainmap.set(Domain::presented("example.com")?, get_certificate());
428	///
429	/// assert!(!domainmap.is_empty());
430	/// # Ok(())
431	/// # }
432	/// ```
433	#[must_use]
434	pub fn is_empty(&self) -> bool {
435		self.len() == 0
436	}
437
438	/// Return an iterator over references to this map's key-value pairs in
439	/// unspecified order
440	///
441	/// # Examples
442	///
443	/// ```rust
444	/// # use links_domainmap::{DomainMap, Domain, ParseError};
445	/// # fn main() -> Result<(), ParseError> {
446	/// let mut domainmap = DomainMap::<u32>::new();
447	/// domainmap.set(Domain::presented("example.com")?, 1);
448	/// let mut iterator = domainmap.iter();
449	///
450	/// assert_eq!(
451	/// 	iterator.next(),
452	/// 	Some((&Domain::presented("example.com")?, &1))
453	/// );
454	/// assert_eq!(iterator.next(), None);
455	/// # Ok(())
456	/// # }
457	/// ```
458	#[must_use]
459	pub fn iter(&self) -> Iter<'_, T> {
460		<&Self as IntoIterator>::into_iter(self)
461	}
462
463	/// Return an iterator over mutable references to this map's key-value pairs
464	/// in unspecified order
465	///
466	/// # Examples
467	///
468	/// ```rust
469	/// # use links_domainmap::{DomainMap, Domain, ParseError};
470	/// # fn main() -> Result<(), ParseError> {
471	/// let mut domainmap = DomainMap::<u32>::new();
472	/// domainmap.set(Domain::presented("example.com")?, 1);
473	/// let mut iterator = domainmap.iter_mut();
474	///
475	/// assert_eq!(
476	/// 	iterator.next(),
477	/// 	Some((&Domain::presented("example.com")?, &mut 1))
478	/// );
479	/// assert_eq!(iterator.next(), None);
480	/// # Ok(())
481	/// # }
482	/// ```
483	#[must_use]
484	pub fn iter_mut(&mut self) -> IterMut<'_, T> {
485		<&mut Self as IntoIterator>::into_iter(self)
486	}
487}
488
489impl<T> Default for DomainMap<T> {
490	fn default() -> Self {
491		Self::with_capacity(4)
492	}
493}
494
495impl<T: PartialEq> PartialEq for DomainMap<T> {
496	fn eq(&self, other: &Self) -> bool {
497		if self.len() != other.len() {
498			return false;
499		}
500
501		self.iter()
502			.all(|(key, value)| other.get_eq(key) == Some(value))
503	}
504}
505
506impl<T: Eq> Eq for DomainMap<T> {}
507
508impl<T: Hash> Hash for DomainMap<T> {
509	fn hash<H: Hasher>(&self, state: &mut H) {
510		let mut sorted = self.data.iter().collect::<Vec<&(Domain, T)>>();
511		sorted.sort_unstable_by_key(|(domain, _)| domain);
512
513		for element in sorted {
514			(*element).hash(state);
515		}
516	}
517}
518
519impl<T> FromIterator<(Domain, T)> for DomainMap<T> {
520	fn from_iter<I: IntoIterator<Item = (Domain, T)>>(iter: I) -> Self {
521		let iter = iter.into_iter();
522		let mut map = Self::with_capacity(iter.size_hint().0);
523
524		for (domain, value) in iter {
525			map.set(domain, value);
526		}
527
528		map
529	}
530}
531
532impl<T> Extend<(Domain, T)> for DomainMap<T> {
533	fn extend<I: IntoIterator<Item = (Domain, T)>>(&mut self, iter: I) {
534		for (domain, value) in iter {
535			self.set(domain, value);
536		}
537	}
538}
539
540impl<T> IntoIterator for DomainMap<T> {
541	type IntoIter = IntoIter<T>;
542	type Item = (Domain, T);
543
544	fn into_iter(self) -> Self::IntoIter {
545		IntoIter {
546			inner: self.data.into_iter(),
547		}
548	}
549}
550
551impl<'a, T: 'a> IntoIterator for &'a DomainMap<T> {
552	type IntoIter = Iter<'a, T>;
553	type Item = (&'a Domain, &'a T);
554
555	fn into_iter(self) -> Self::IntoIter {
556		Iter {
557			inner: self.data.iter(),
558		}
559	}
560}
561
562impl<'a, T: 'a> IntoIterator for &'a mut DomainMap<T> {
563	type IntoIter = IterMut<'a, T>;
564	type Item = (&'a Domain, &'a mut T);
565
566	fn into_iter(self) -> Self::IntoIter {
567		IterMut {
568			inner: self.data.iter_mut(),
569		}
570	}
571}
572
573pub struct IntoIter<T> {
574	inner: VecIter<(Domain, T)>,
575}
576
577impl<T> Iterator for IntoIter<T> {
578	type Item = (Domain, T);
579
580	fn next(&mut self) -> Option<Self::Item> {
581		self.inner.next()
582	}
583}
584
585pub struct Iter<'a, T: 'a> {
586	inner: SliceIter<'a, (Domain, T)>,
587}
588
589impl<'a, T: 'a> Iterator for Iter<'a, T> {
590	type Item = (&'a Domain, &'a T);
591
592	fn next(&mut self) -> Option<Self::Item> {
593		self.inner.next().map(|(k, v)| (k, v))
594	}
595}
596
597pub struct IterMut<'a, T: 'a> {
598	inner: SliceIterMut<'a, (Domain, T)>,
599}
600
601impl<'a, T: 'a> Iterator for IterMut<'a, T> {
602	type Item = (&'a Domain, &'a mut T);
603
604	fn next(&mut self) -> Option<Self::Item> {
605		self.inner.next().map(|(k, v)| (&*k, v))
606	}
607}
608
609#[cfg(test)]
610mod tests {
611	use alloc::format;
612
613	use super::*;
614
615	#[test]
616	fn domainmap_new() {
617		for map in [
618			DomainMap::<()>::new(),
619			DomainMap::<()>::default(),
620			DomainMap::<()>::with_capacity(8),
621		] {
622			assert!(map.is_empty());
623			assert_eq!(map.len(), 0);
624
625			assert!(map
626				.get(&Domain::reference("example.com").unwrap())
627				.is_none());
628		}
629	}
630
631	#[test]
632	fn domainmap_get() {
633		let mut map = DomainMap::<u32>::new();
634
635		assert_eq!(map.get(&Domain::reference("example.com").unwrap()), None);
636		assert_eq!(
637			map.get(&Domain::reference("foo.example.com").unwrap()),
638			None
639		);
640
641		map.set(Domain::presented("example.com").unwrap(), 1);
642		map.set(Domain::presented("*.example.com").unwrap(), 10);
643
644		assert_eq!(
645			map.get(&Domain::reference("example.com").unwrap()),
646			Some(&1)
647		);
648		assert_eq!(
649			map.get(&Domain::reference("foo.example.com").unwrap()),
650			Some(&10)
651		);
652	}
653
654	#[test]
655	fn domainmap_get_mut() {
656		let mut map = DomainMap::<u32>::new();
657
658		assert_eq!(
659			map.get_mut(&Domain::reference("example.com").unwrap()),
660			None
661		);
662		assert_eq!(
663			map.get_mut(&Domain::reference("foo.example.com").unwrap()),
664			None
665		);
666
667		map.set(Domain::presented("example.com").unwrap(), 1);
668		map.set(Domain::presented("*.example.com").unwrap(), 10);
669
670		assert_eq!(
671			map.get_mut(&Domain::reference("example.com").unwrap()),
672			Some(&mut 1)
673		);
674
675		let val = map
676			.get_mut(&Domain::reference("example.com").unwrap())
677			.unwrap();
678		*val += 100;
679
680		let foo_val = map
681			.get_mut(&Domain::reference("foo.example.com").unwrap())
682			.unwrap();
683		*foo_val += 100;
684
685		assert_eq!(
686			map.get_mut(&Domain::reference("example.com").unwrap()),
687			Some(&mut 101)
688		);
689		assert_eq!(
690			map.get_mut(&Domain::reference("foo.example.com").unwrap()),
691			Some(&mut 110)
692		);
693	}
694
695	#[test]
696	fn domainmap_get_eq() {
697		let mut map = DomainMap::<u32>::new();
698
699		assert_eq!(
700			map.get_eq(&Domain::presented("*.example.com").unwrap()),
701			None
702		);
703		assert_eq!(
704			map.get_eq(&Domain::reference("foo.example.com").unwrap()),
705			None
706		);
707
708		map.set(Domain::presented("*.example.com").unwrap(), 1);
709
710		assert_eq!(
711			map.get_eq(&Domain::presented("*.example.com").unwrap()),
712			Some(&1)
713		);
714		assert_eq!(
715			map.get_eq(&Domain::reference("foo.example.com").unwrap()),
716			None
717		);
718	}
719
720	#[test]
721	fn domainmap_set() {
722		let mut map = DomainMap::<u32>::new();
723
724		assert_eq!(map.set(Domain::presented("example.com").unwrap(), 1), None);
725		assert_eq!(
726			map.set(Domain::presented("*.example.com").unwrap(), 10),
727			None
728		);
729
730		assert_eq!(
731			map.get(&Domain::reference("example.com").unwrap()),
732			Some(&1)
733		);
734		assert_eq!(
735			map.get(&Domain::reference("foo.example.com").unwrap()),
736			Some(&10)
737		);
738
739		assert_eq!(
740			map.set(Domain::presented("*.example.com").unwrap(), 20),
741			Some(10)
742		);
743		assert_eq!(
744			map.set(Domain::presented("example.com").unwrap(), 2),
745			Some(1)
746		);
747		assert_eq!(
748			map.set(Domain::presented("foo.example.com").unwrap(), 200),
749			None
750		);
751
752		assert_eq!(
753			map.get(&Domain::reference("example.com").unwrap()),
754			Some(&2)
755		);
756		assert_eq!(
757			map.get(&Domain::reference("foo.example.com").unwrap()),
758			Some(&200)
759		);
760	}
761
762	#[test]
763	fn domainmap_remove() {
764		let mut map = DomainMap::<u32>::new();
765
766		map.set(Domain::presented("example.com").unwrap(), 1);
767		map.set(Domain::presented("*.example.com").unwrap(), 10);
768
769		assert_eq!(map.len(), 2);
770
771		assert_eq!(
772			map.remove(&Domain::presented("example.com").unwrap()),
773			Some(1)
774		);
775		assert_eq!(
776			map.remove(&Domain::presented("foo.example.com").unwrap()),
777			None
778		);
779
780		assert_eq!(map.len(), 1);
781		assert_eq!(map.get(&Domain::reference("example.com").unwrap()), None);
782		assert_eq!(
783			map.get(&Domain::reference("foo.example.com").unwrap()),
784			Some(&10)
785		);
786
787		assert_eq!(
788			map.remove(&Domain::presented("*.example.com").unwrap()),
789			Some(10)
790		);
791
792		assert_eq!(map.len(), 0);
793		assert_eq!(
794			map.get(&Domain::reference("foo.example.com").unwrap()),
795			None
796		);
797	}
798
799	#[test]
800	fn domainmap_len_clear() {
801		let mut map = DomainMap::<u32>::new();
802
803		assert!(map.is_empty());
804		assert_eq!(map.len(), 0);
805
806		map.set(Domain::presented("example.com").unwrap(), 1);
807		map.set(Domain::presented("*.example.com").unwrap(), 10);
808		map.set(Domain::presented("foo.example.com").unwrap(), 100);
809
810		assert!(!map.is_empty());
811		assert_eq!(map.len(), 3);
812
813		map.clear();
814
815		assert!(map.is_empty());
816		assert_eq!(map.len(), 0);
817	}
818
819	#[test]
820	fn domainmap_iter() {
821		let mut map = DomainMap::<u32>::new();
822
823		let a = Domain::presented("example.com").unwrap();
824		let b = Domain::presented("*.example.com").unwrap();
825		let c = Domain::presented("foo.example.com").unwrap();
826
827		map.set(a.clone(), 1);
828		map.set(b.clone(), 10);
829		map.set(c.clone(), 100);
830
831		#[allow(clippy::explicit_iter_loop)]
832		for (domain, value) in map.iter() {
833			// Iteration order is not specified
834			assert!(
835				(*domain == a && *value == 1)
836					|| (*domain == b && *value == 10)
837					|| (*domain == c && *value == 100)
838			);
839		}
840
841		for (domain, value) in &map {
842			// Iteration order is not specified
843			assert!(
844				(*domain == a && *value == 1)
845					|| (*domain == b && *value == 10)
846					|| (*domain == c && *value == 100)
847			);
848		}
849
850		#[allow(clippy::explicit_iter_loop)]
851		for (domain, value) in map.iter_mut() {
852			// Iteration order is not specified
853			assert!(
854				(*domain == a && *value == 1)
855					|| (*domain == b && *value == 10)
856					|| (*domain == c && *value == 100)
857			);
858
859			*value += 300;
860		}
861		for (domain, value) in &mut map {
862			// Iteration order is not specified
863			assert!(
864				(*domain == a && *value == 301)
865					|| (*domain == b && *value == 310)
866					|| (*domain == c && *value == 400)
867			);
868
869			*value += 700;
870		}
871
872		#[allow(clippy::explicit_into_iter_loop)]
873		for (domain, value) in map.clone().into_iter() {
874			// Iteration order is not specified
875			assert!(
876				(domain == a && value == 1001)
877					|| (domain == b && value == 1010)
878					|| (domain == c && value == 1100)
879			);
880
881			drop(domain);
882		}
883
884		for (domain, value) in map {
885			// Iteration order is not specified
886			assert!(
887				(domain == a && value == 1001)
888					|| (domain == b && value == 1010)
889					|| (domain == c && value == 1100)
890			);
891
892			drop(domain);
893		}
894
895		map = DomainMap::<u32>::new();
896
897		let a = Domain::presented("example.net").unwrap();
898		let b = Domain::presented("*.example.net").unwrap();
899		let c = Domain::presented("foo.example.net").unwrap();
900
901		map.set(a.clone(), 1);
902		map.set(b.clone(), 10);
903		map.set(c.clone(), 100);
904
905		for (domain, value) in &map {
906			// Iteration order is not specified
907			assert!(
908				(*domain == a && *value == 1)
909					|| (*domain == b && *value == 10)
910					|| (*domain == c && *value == 100)
911			);
912		}
913
914		for (domain, value) in &mut map {
915			// Iteration order is not specified
916			assert!(
917				(*domain == a && *value == 1)
918					|| (*domain == b && *value == 10)
919					|| (*domain == c && *value == 100)
920			);
921
922			*value += 1000;
923		}
924
925		for (domain, value) in map {
926			// Iteration order is not specified
927			assert!(
928				(domain == a && value == 1001)
929					|| (domain == b && value == 1010)
930					|| (domain == c && value == 1100)
931			);
932
933			drop(domain);
934		}
935	}
936
937	#[test]
938	#[allow(clippy::many_single_char_names)]
939	fn domainmap_from_iter_extend() {
940		let a = Domain::presented("example.net").unwrap();
941		let b = Domain::presented("*.example.net").unwrap();
942		let c = Domain::presented("foo.example.net").unwrap();
943		let e = Domain::presented("example.com").unwrap();
944		let d = Domain::presented("bar.example.com").unwrap();
945
946		let mut map = DomainMap::<u32>::from_iter([(a, 1), (b, 10), (c, 100)]);
947
948		assert_eq!(map.len(), 3);
949
950		map.extend([(e, 1000), (d, 10000)]);
951
952		assert_eq!(map.len(), 5);
953	}
954
955	#[test]
956	fn domainmap_misc_traits() {
957		let mut map = DomainMap::<u32>::new();
958		let mut other = DomainMap::<u32>::new();
959
960		let a = Domain::presented("example.com").unwrap();
961		let b = Domain::presented("*.example.com").unwrap();
962		let c = Domain::presented("foo.example.com").unwrap();
963
964		map.set(a.clone(), 1);
965		map.set(b.clone(), 10);
966		map.set(c.clone(), 100);
967
968		other.set(c, 100);
969		other.set(b, 10);
970		other.set(a, 1);
971
972		assert!(format!("{map:?}").contains("DomainMap"));
973
974		let cloned = map.clone();
975		assert!(map == cloned);
976		assert!(map == other);
977		assert!(map == map);
978		assert!(map != DomainMap::new());
979	}
980}