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}