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}