fqdn_trie/set.rs
1use std::iter::FromIterator;
2use std::num::NonZeroUsize;
3use std::ops::Index;
4
5use crate::{HasFqdn, Fqdn};
6use crate::trie::InnerTrie;
7
8/// A set of FQDN based on a suffix trie
9pub struct FqdnTrieSet<T:AsRef<Fqdn>> {
10 inner: InnerTrie<TrieSetElt<T>>
11}
12
13struct TrieSetElt<T:AsRef<Fqdn>>(T);
14impl<T:AsRef<Fqdn>> HasFqdn for TrieSetElt<T> {
15 #[inline] fn fqdn(&self) -> &Fqdn { self.0.as_ref() }
16}
17
18impl<T:AsRef<Fqdn>> FqdnTrieSet<T> {
19
20 /// Creates a new set with the root element.
21 ///
22 /// # Panics
23 /// Panics if the FQDN of the root element is not the empty one (`.`)
24 #[inline]
25 pub fn new(root: T) -> Self
26 {
27 Self { inner: InnerTrie::new(TrieSetElt(root)) }
28 }
29
30 /// Creates a new set with the root element and an initial capacity.
31 ///
32 /// # Panics
33 /// Panics if the FQDN of the root element is not the empty one (`.`)
34 #[inline]
35 pub fn with_capacity(root: T, capacity: usize) -> Self
36 {
37 Self { inner: InnerTrie::with_capacity(TrieSetElt(root), capacity) }
38 }
39
40 /// Reserves capacity for at least additional more elements to be inserted in the set.
41 /// The collection may reserve more space to speculatively avoid frequent reallocations.
42 /// After calling reserve, capacity will be greater than or equal to `self.len() + additional`.
43 /// Does nothing if capacity is already sufficient.
44 ///
45 /// # Panics
46 /// Panics if the new allocation size overflows usize.
47 ///
48 /// # Example
49 /// ```
50 /// use fqdn::FQDN;
51 /// use fqdn_trie::FqdnTrieSet;
52 /// let mut fqdns = FqdnTrieSet::<FQDN>::default();
53 /// fqdns.reserve(100);
54 /// ```
55 #[inline]
56 pub fn reserve(&mut self, additional: usize)
57 {
58 self.inner.reserve(additional)
59 }
60
61 /// Shrinks the capacity of the trie as much as possible.
62 /// It will drop down as much as possible while maintaining the internal rules
63 /// and possibly leaving some space in accordance with the resize policy.
64 #[inline]
65 pub fn shrink_to_fit(&mut self)
66 {
67 self.inner.shrink_to_fit()
68 }
69
70 /// Gets the number of element of this set.
71 ///
72 /// As a trie always contains a top element (the element associated to the
73 /// top/empty domain), the length never equals zero.
74 #[inline]
75 pub fn len(&self) -> NonZeroUsize
76 {
77 unsafe {
78 NonZeroUsize::new_unchecked(self.inner.len())
79 }
80 }
81
82 /// Gets the element, if any, which exactly matches (i.e. equals) the given FQDN.
83 ///
84 /// To find the longuest parent domain, consider [`Self::lookup`]
85 ///
86 /// # Example
87 /// ```
88 /// use fqdn::{fqdn,FQDN};
89 /// use fqdn_trie::FqdnTrieSet;
90 ///
91 /// let mut fqdns = FqdnTrieSet::<FQDN>::default();
92 /// fqdns.insert(fqdn!("orange.com"));
93 /// fqdns.insert(fqdn!("mail.orange.com"));
94 ///
95 /// assert!( fqdns.get(fqdn!("orange.com")).is_some() );
96 /// assert!( fqdns.get(fqdn!("www.orange.com")).is_none() );
97 /// ```
98 #[inline]
99 pub fn get<K: AsRef<Fqdn>>(&self, look: K) -> Option<&T>
100 {
101 self.inner.get_exact_leaf(look.as_ref()).map(|x| &x.0)
102 }
103
104 /// Gets an iterator over all the stored FQDN
105 pub fn iter(&self) -> impl Iterator<Item=&T>
106 {
107 self.inner.iter().map(|x| &x.0)
108 }
109
110 /// Gets the element which the longuest parent domain of the given FQDN.
111 ///
112 /// To use an exact match, consider [`Self::get`]
113 ///
114 /// # Example
115 /// ```
116 /// use fqdn::{fqdn,FQDN};
117 /// use fqdn_trie::FqdnTrieSet;
118 ///
119 /// let mut fqdns = FqdnTrieSet::<FQDN>::default();
120 /// fqdns.insert(fqdn!("orange.com"));
121 /// fqdns.insert(fqdn!("mail.orange.com"));
122 ///
123 /// assert_eq!( *fqdns.lookup(fqdn!("orange.com")), fqdn!("orange.com") );
124 /// assert_eq!( *fqdns.lookup(fqdn!("www.orange.com")), fqdn!("orange.com") );
125 /// assert_eq!( *fqdns.lookup(fqdn!("blue.com")), fqdn!(".") );
126 /// ```
127 #[inline]
128 pub fn lookup<K:AsRef<Fqdn>>(&self, look: K) -> &T
129 {
130 &self.inner.lookup(look.as_ref()).0
131 }
132
133 /// Adds a new element in the set.
134 ///
135 /// Returns `true` if the element is effectively added and `false` if an element with the same
136 /// FQDN is already present in the set (which remains unmodified)
137 ///
138 /// To replace an already present element, consider [`Self::replace`]
139 ///
140 /// # Example
141 /// ```
142 /// use fqdn::{fqdn,FQDN};
143 /// use fqdn_trie::FqdnTrieSet;
144 ///
145 /// let mut fqdns = FqdnTrieSet::<FQDN>::default();
146 ///
147 /// assert!(fqdns.insert(fqdn!("orange.com")));
148 /// assert!( ! fqdns.insert(fqdn!("orange.com")));
149 /// ```
150 #[inline]
151 pub fn insert(&mut self, added: T) -> bool
152 {
153 self.inner.insert(TrieSetElt(added))
154 }
155
156 /// Adds a value to the set, replacing the existing element, if any,
157 /// that is associated to the same FQDN. Returns the replaced element.
158 ///
159 /// # Example
160 /// ```
161 /// use fqdn::{fqdn,FQDN};
162 /// use fqdn_trie::FqdnTrieSet;
163 ///
164 /// let mut fqdns = FqdnTrieSet::<FQDN>::default();
165 ///
166 /// assert!(fqdns.replace(fqdn!("orange.com")).is_none());
167 /// assert!(fqdns.replace(fqdn!("orange.com")).is_some());
168 /// ```
169 #[inline]
170 pub fn replace(&mut self, value: T) -> Option<T>
171 {
172 self.inner.replace(TrieSetElt(value)).map(|x| x.0)
173 }
174
175 /// If the set contains an element is to the FQDN, removes it from the set and drops it.
176 /// Returns whether such an element was present.
177 ///
178 /// # Example
179 /// ```
180 /// use fqdn::{fqdn,FQDN};
181 /// use fqdn_trie::FqdnTrieSet;
182 ///
183 /// let mut fqdns = FqdnTrieSet::<FQDN>::default();
184 /// fqdns.insert(fqdn!("orange.com"));
185 ///
186 /// assert!(fqdns.remove(fqdn!("orange.com")));
187 /// assert!( ! fqdns.remove(fqdn!("orange.com")));
188 /// ```
189 #[inline]
190 pub fn remove<K:AsRef<Fqdn>>(&mut self, removed: K) -> bool
191 {
192 self.inner.remove(removed.as_ref()).is_some()
193 }
194
195 /// Removes and returns the element in the set, if any, that is associated to the FQDN.
196 ///
197 /// # Example
198 /// ```
199 /// use fqdn::{fqdn,FQDN};
200 /// use fqdn_trie::FqdnTrieSet;
201 ///
202 /// let mut fqdns = FqdnTrieSet::<FQDN>::default();
203 /// fqdns.insert(fqdn!("orange.com"));
204 ///
205 /// assert!(fqdns.take(fqdn!("orange.com")).is_some());
206 /// assert!(fqdns.take(fqdn!("orange.com")).is_none());
207 /// ```
208 #[inline]
209 pub fn take<K:AsRef<Fqdn>>(&mut self, removed: K) -> Option<T>
210 {
211 self.inner.remove(removed.as_ref()).map(|x| x.0)
212 }
213
214 /// Prints the trie structure in graphviz format.
215 ///
216 /// If a file name is specified, the graphviz file is generated.
217 /// If not, the output is redirected to standard output.
218 #[cfg(feature= "graphviz")]
219 pub fn generate_graphviz_file(&self, file: Option<&str>) -> std::io::Result<()> { self.inner.generate_graphviz_file(file) }
220
221 /// Generates the trie structure in a pdf file using `dot` command.
222 ///
223 /// If a file name is specified, the pdf file is generated.
224 /// If not, the output is redirected to standard output.
225 ///
226 /// # Panics
227 /// Panics if the `dot` command was not found.
228 #[cfg(feature= "graphviz")]
229 pub fn generate_pdf_file(&self, file: Option<&str>) -> std::io::Result<()> { self.inner.generate_pdf_file(file) }
230
231 #[doc(hidden)]
232 #[cfg(target_os = "macos")]
233 #[cfg(feature= "graphviz")]
234 pub fn open_dot_view(&self) -> std::io::Result<()>
235 {
236 self.inner.open_dot_view()
237 }
238}
239
240impl<T:AsRef<Fqdn>> Extend<T> for FqdnTrieSet<T>
241{
242 fn extend<I: IntoIterator<Item=T>>(&mut self, iter: I)
243 {
244 iter.into_iter()
245 .for_each(| item | { self.replace(item); } )
246 }
247}
248
249impl<T:AsRef<Fqdn>+Default> FromIterator<T> for FqdnTrieSet<T>
250{
251 fn from_iter<I:IntoIterator<Item=T>>(iter: I) -> Self
252 {
253 let mut trieset = Self::new(T::default());
254 trieset.extend(iter);
255 trieset
256 }
257}
258
259impl<T:AsRef<Fqdn>+Default> Default for FqdnTrieSet<T>
260{
261 #[inline]
262 fn default() -> Self { Self::new(T::default()) }
263}
264
265impl<I:AsRef<Fqdn>,T:AsRef<Fqdn>> Index<I> for FqdnTrieSet<T>
266{
267 type Output = T;
268
269 /// Returns a reference to the value corresponding to the
270 /// longuest parent domain of the supplied FQDN (see [`Self::lookup`]).
271 ///
272 /// It never fails.
273 #[inline]
274 fn index(&self, index: I) -> &Self::Output {
275 self.lookup(index)
276 }
277}