has_some/
lib.rs

1//! A very simple trait that relieves some tiresome things about using `is_empty` in iterator
2//! filters and other "not `is_empty`" contexts.
3//!
4//! Three annoyances are covered:
5//!
6//!   * Having to always code `!T.is_empty()` when it's clearer to have `T.has_some()`;
7//!   * Having to code a closure in `Iterator::filter` for the above semantics, rather
8//!     than just passing a function
9//!   * Having to code a closure in `Iterator::filter` even for `T.is_empty` when the `Item`
10//!     of the iterator is a reference (or a double reference!).
11//!
12//! I fully admit that the implementation is banal - but it works!
13//!
14//! # Examples
15//!
16//! ## When you want to know if a collection has some elements
17//!
18//! Before:
19//!
20//! ```
21//! let empty_string = "";
22//! let not_empty_string = "this is not empty";
23//! assert!(empty_string.is_empty());
24//! assert!(!not_empty_string.is_empty());
25//! ```
26//! Now:
27//!
28//! ```
29//! use has_some::HasSome;
30//! let empty_string = "";
31//! let not_empty_string = "this is not empty";
32//! assert!(empty_string.is_empty());
33//! assert!(not_empty_string.has_some());
34//! ```
35//!
36//! ## When you have an iterator that emits owned types as items
37//!
38//! Before:
39//!
40//! ```
41//! let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
42//! let vector2 = vector.clone();
43//!
44//! let empties: Vec<String> = vector.into_iter().filter(String::is_empty).collect();
45//! let not_empties: Vec<String> = vector2.into_iter().filter(|s|!s.is_empty()).collect();
46//!
47//! assert_eq!([""], empties.as_slice());
48//! assert_eq!(["some_data", "more data"], not_empties.as_slice());
49//! ```
50//!
51//! Now:
52//!
53//! ```
54//! use has_some::HasSome;
55//! let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
56//! let vector2 = vector.clone();
57//!
58//! let empties: Vec<String> = vector.into_iter().filter(String::is_empty).collect();
59//! let not_empties: Vec<String> = vector2.into_iter().filter(String::has_some).collect();
60//!
61//! assert_eq!([""], empties.as_slice());
62//! assert_eq!(["some_data", "more data"], not_empties.as_slice());
63//! ```
64//!
65//! ## When you have an iterator that emits reference types as items
66//!
67//! Before:
68//!
69//! ```
70//! let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
71//!
72//! let empties: Vec<&String> = vector.iter().filter(|s|s.is_empty()).collect();
73//! let not_empties: Vec<&String> = vector.iter().filter(|s|!s.is_empty()).collect();
74//!
75//! assert_eq!([""], empties.as_slice());
76//! assert_eq!(["some_data", "more data"], not_empties.as_slice());
77//! ```
78//!
79//! Now:
80//!
81//! ```
82//! use has_some::HasSome;
83//! let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
84//!
85//! let empties: Vec<&String> = vector.iter().filter(String::is_empty2).collect();
86//! let not_empties: Vec<&String> = vector.iter().filter(String::has_some2).collect();
87//!
88//! assert_eq!([""], empties.as_slice());
89//! assert_eq!(["some_data", "more data"], not_empties.as_slice());
90//! ```
91//!
92//! Or even those pesky double references:
93//!
94//! ```
95//! use has_some::HasSome;
96//! let vector = vec!["some_data", "", "more data"];
97//!
98//! let empties: Vec<&&str> = vector.iter().filter(str::is_empty3).collect();
99//! let not_empties: Vec<&&str> = vector.iter().filter(str::has_some3).collect();
100//!
101//! assert_eq!([&""], empties.as_slice());
102//! assert_eq!([&"some_data", &"more data"], not_empties.as_slice());
103//! ```
104//!
105pub trait HasSome {
106    /// The opposite to `T:is_empty`.
107    ///
108    /// Usually implemented as `!self.is_empty()`, but as that method
109    /// is not defined by a Trait in stable Rust, this needs re-implementing
110    /// for each type that requires it.
111    ///
112    /// # Examples
113    /// ```
114    /// use has_some::HasSome;
115    ///
116    /// assert!("this is not empty".has_some());
117    /// ```
118    ///
119    /// ```
120    /// use has_some::HasSome;
121    /// let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
122    ///
123    /// let not_empties: Vec<String> = vector.into_iter().filter(String::has_some).collect();
124    ///
125    /// assert_eq!(["some_data","more data"], not_empties.as_slice());
126    /// ```
127    fn has_some(&self) -> bool;
128
129    /// `is_empty` in a form that is suitable for use in `Iterator::filter` where
130    /// `Item = &OwnedType` (e.g. `&String`)
131    ///
132    /// # Examples
133    ///
134    /// ```
135    /// use has_some::HasSome;
136    /// let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
137    ///
138    /// let empties: Vec<&String> = vector.iter().filter(String::is_empty2).collect();
139    ///
140    /// assert_eq!([""], empties.as_slice());
141    /// ```
142    fn is_empty2(self: &&Self) -> bool;
143
144    /// `is_empty` in a form that is suitable for use in `Iterator::filter` where
145    /// `Item = &RefType` (e.g. `&&str`)
146    ///
147    /// # Examples
148    ///
149    /// ```
150    /// use has_some::HasSome;
151    /// let vector = vec!["some_data", "", "more data"];
152    ///
153    /// let empties: Vec<&&str> = vector.iter().filter(str::is_empty3).collect();
154    ///
155    /// assert_eq!([&""], empties.as_slice());
156    /// ```
157    fn is_empty3(self: &&&Self) -> bool {
158        (*self).is_empty2()
159    }
160
161    /// `has_some` in a form that is suitable for use in `Iterator::filter` where
162    /// `Item = &OwnedType` (e.g. `&String`)
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// use has_some::HasSome;
168    /// let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
169    ///
170    /// let not_empties: Vec<&String> = vector.iter().filter(String::has_some2).collect();
171    ///
172    /// assert_eq!(["some_data","more data"], not_empties.as_slice());
173    /// ```
174    fn has_some2(self: &&Self) -> bool {
175        (*self).has_some()
176    }
177
178    /// `has_some` in a form that is suitable for use in `Iterator::filter` where
179    /// `Item = &RefType` (e.g. `&&str`)
180    ///
181    /// # Examples
182    ///
183    /// ```
184    /// use has_some::HasSome;
185    /// let vector = vec!["some_data", "", "more data"];
186    ///
187    /// let not_empties: Vec<&&str> = vector.iter().filter(str::has_some3).collect();
188    ///
189    /// assert_eq!([&"some_data", &"more data"], not_empties.as_slice());
190    /// ```
191    fn has_some3(self: &&&Self) -> bool {
192        (*self).has_some()
193    }
194}
195impl HasSome for str {
196    fn has_some(&self) -> bool {
197        !self.is_empty()
198    }
199    fn is_empty2(self: &&Self) -> bool {
200        (*self).is_empty()
201    }
202}
203impl HasSome for ::std::ffi::CStr {
204    fn has_some(&self) -> bool {
205        !self.is_empty()
206    }
207    fn is_empty2(self: &&Self) -> bool {
208        (*self).is_empty()
209    }
210}
211impl HasSome for ::std::string::String {
212    fn has_some(&self) -> bool {
213        !self.is_empty()
214    }
215    fn is_empty2(self: &&Self) -> bool {
216        (*self).is_empty()
217    }
218}
219impl<Idx: PartialOrd<Idx>> HasSome for ::std::ops::Range<Idx> {
220    fn has_some(&self) -> bool {
221        !self.is_empty()
222    }
223    fn is_empty2(self: &&Self) -> bool {
224        (*self).is_empty()
225    }
226}
227impl<Idx: PartialOrd<Idx>> HasSome for ::std::ops::RangeInclusive<Idx> {
228    fn has_some(&self) -> bool {
229        !self.is_empty()
230    }
231    fn is_empty2(self: &&Self) -> bool {
232        (*self).is_empty()
233    }
234}
235impl<K, V, S: ::std::hash::BuildHasher> HasSome for ::std::collections::hash_map::HashMap<K, V, S> {
236    fn has_some(&self) -> bool {
237        !self.is_empty()
238    }
239    fn is_empty2(self: &&Self) -> bool {
240        (*self).is_empty()
241    }
242}
243impl<K, V> HasSome for ::std::collections::BTreeMap<K, V> {
244    fn has_some(&self) -> bool {
245        !self.is_empty()
246    }
247    fn is_empty2(self: &&Self) -> bool {
248        (*self).is_empty()
249    }
250}
251impl<T, S: ::std::hash::BuildHasher> HasSome for ::std::collections::hash_set::HashSet<T, S> {
252    fn has_some(&self) -> bool {
253        !self.is_empty()
254    }
255    fn is_empty2(self: &&Self) -> bool {
256        (*self).is_empty()
257    }
258}
259impl<T> HasSome for [T] {
260    fn has_some(&self) -> bool {
261        !self.is_empty()
262    }
263    fn is_empty2(self: &&Self) -> bool {
264        (*self).is_empty()
265    }
266}
267impl<T> HasSome for ::std::collections::BinaryHeap<T> {
268    fn has_some(&self) -> bool {
269        !self.is_empty()
270    }
271    fn is_empty2(self: &&Self) -> bool {
272        (*self).is_empty()
273    }
274}
275impl<T> HasSome for ::std::collections::BTreeSet<T> {
276    fn has_some(&self) -> bool {
277        !self.is_empty()
278    }
279    fn is_empty2(self: &&Self) -> bool {
280        (*self).is_empty()
281    }
282}
283impl<T> HasSome for ::std::collections::LinkedList<T> {
284    fn has_some(&self) -> bool {
285        !self.is_empty()
286    }
287    fn is_empty2(self: &&Self) -> bool {
288        (*self).is_empty()
289    }
290}
291impl<T> HasSome for ::std::collections::VecDeque<T> {
292    fn has_some(&self) -> bool {
293        !self.is_empty()
294    }
295    fn is_empty2(self: &&Self) -> bool {
296        (*self).is_empty()
297    }
298}
299impl<T> HasSome for ::std::vec::Vec<T> {
300    fn has_some(&self) -> bool {
301        !self.is_empty()
302    }
303    fn is_empty2(self: &&Self) -> bool {
304        (*self).is_empty()
305    }
306}
307
308/// The rare case where `is_empty` consumes `self`.
309pub trait HasSomeConsume {
310    fn has_some(self) -> bool;
311    fn is_empty1(&self) -> bool;
312    fn has_some1(&self) -> bool;
313}
314impl<T> HasSomeConsume for ::std::ptr::NonNull<[T]> {
315    fn has_some(self) -> bool {
316        !self.is_empty()
317    }
318    fn is_empty1(&self) -> bool {
319        (*self).is_empty()
320    }
321    fn has_some1(&self) -> bool {
322        !(*self).is_empty()
323    }
324}
325
326//Used for proc macs
327//impl HasSome for TokenStream { fn has_some(&self) -> bool { !self.is_empty() } }
328
329//The issue #35428 is EIGHT years old at writing!!! - it will supersede all the above except the top two if it ever gets finalized
330//impl<T: ExactSizeIterator> HasSome for T { fn has_some(&self) -> bool { !self.is_empty() } }
331
332//The issue #76915 is FOUR years old at writing!!!
333//impl<'a> HasSome for ::std::os::unix::net::SocketAncillary<'a> { fn has_some(&self) -> bool { !self.is_empty() } }
334
335//The issue #76915 is only 11 months old years old at writing, though the last comment was 8 months ago
336//impl HasSome for ::std::ffi::os_str::OsStr { fn has_some(&self) -> bool { !self.is_empty() } }
337
338#[cfg(test)]
339mod tests {
340    #[test]
341    fn test_owned_items() {
342        use super::HasSome;
343        let vector = vec![
344            "some_data".to_owned(),
345            "".to_owned(),
346            "more data".to_owned(),
347            "".to_owned(),
348        ];
349        let vector2 = vector.clone();
350        // If you want the empties, get can do
351        let empties = vector
352            .into_iter()
353            .filter(String::is_empty)
354            .collect::<Vec<String>>();
355        assert_eq!(["", ""], empties.as_slice());
356        // But If you want the non-empties, get can do
357        let non_empties = vector2
358            .into_iter()
359            .filter(String::has_some)
360            .collect::<Vec<String>>();
361        assert_eq!(["some_data", "more data"], non_empties.as_slice());
362    }
363
364    #[test]
365    fn test_ref_items() {
366        use super::HasSome;
367        let vector = vec!["some_data", "", "more data", ""];
368        let vector2 = vector.clone();
369        // If you want the empties, get can do
370        let empties = vector
371            .into_iter()
372            .filter(str::is_empty2)
373            .collect::<Vec<&str>>();
374        assert_eq!(["", ""], empties.as_slice());
375        // But If you want the non-empties, get can do
376        let non_empties = vector2
377            .iter()
378            .filter(str::has_some3)
379            .collect::<Vec<&&str>>();
380        assert_eq!([&"some_data", &"more data"], non_empties.as_slice());
381    }
382}