has_some/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
//! A very simple trait that relieves some tiresome things about using `is_empty` in iterator 
//! filters and other "not `is_empty`" contexts.
//! 
//! Three annoyances are covered:
//! 
//!   * Having to always code `!T.is_empty()` when it's clearer to have `T.has_some()`;
//!   * Having to code a closure in `Iterator::filter` for the above semantics, rather
//!     than just passing a function
//!   * Having to code a closure in `Iterator::filter` even for `T.is_empty` when the `Item`
//!     of the iterator is a reference (or a double reference!).
//! 
//! I fully admit that the implementation is banal - but it works!
//! 
//! # Examples
//! 
//! ## When you want to know if a collection has some elements
//! 
//! Before:
//! 
//! ```
//! let empty_string = "";
//! let not_empty_string = "this is not empty";
//! assert!(empty_string.is_empty());
//! assert!(!not_empty_string.is_empty());
//! ```
//! Now:
//! 
//! ```
//! use has_some::HasSome;
//! let empty_string = "";
//! let not_empty_string = "this is not empty";
//! assert!(empty_string.is_empty());
//! assert!(not_empty_string.has_some());
//! ```
//! 
//! ## When you have an iterator that emits owned types as items
//! 
//! Before:
//! 
//! ```
//! let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
//! let vector2 = vector.clone();
//! 
//! let empties: Vec<String> = vector.into_iter().filter(String::is_empty).collect();
//! let not_empties: Vec<String> = vector2.into_iter().filter(|s|!s.is_empty()).collect();
//! 
//! assert_eq!([""], empties.as_slice());
//! assert_eq!(["some_data", "more data"], not_empties.as_slice());
//! ```
//! 
//! Now:
//! 
//! ```
//! use has_some::HasSome;
//! let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
//! let vector2 = vector.clone();
//! 
//! let empties: Vec<String> = vector.into_iter().filter(String::is_empty).collect();
//! let not_empties: Vec<String> = vector2.into_iter().filter(String::has_some).collect();
//! 
//! assert_eq!([""], empties.as_slice());
//! assert_eq!(["some_data", "more data"], not_empties.as_slice());
//! ```
//! 
//! ## When you have an iterator that emits reference types as items
//! 
//! Before:
//! 
//! ```
//! let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
//! 
//! let empties: Vec<&String> = vector.iter().filter(|s|s.is_empty()).collect();
//! let not_empties: Vec<&String> = vector.iter().filter(|s|!s.is_empty()).collect();
//! 
//! assert_eq!([""], empties.as_slice());
//! assert_eq!(["some_data", "more data"], not_empties.as_slice());
//! ```
//! 
//! Now:
//! 
//! ```
//! use has_some::HasSome;
//! let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
//! 
//! let empties: Vec<&String> = vector.iter().filter(String::is_empty2).collect();
//! let not_empties: Vec<&String> = vector.iter().filter(String::has_some2).collect();
//! 
//! assert_eq!([""], empties.as_slice());
//! assert_eq!(["some_data", "more data"], not_empties.as_slice());
//! ```
//! 
//! Or even those pesky double references:
//! 
//! ```
//! use has_some::HasSome;
//! let vector = vec!["some_data", "", "more data"];
//! 
//! let empties: Vec<&&str> = vector.iter().filter(str::is_empty3).collect();
//! let not_empties: Vec<&&str> = vector.iter().filter(str::has_some3).collect();
//! 
//! assert_eq!([&""], empties.as_slice());
//! assert_eq!([&"some_data", &"more data"], not_empties.as_slice());
//! ```
//! 
pub trait HasSome {
	/// The opposite to `T:is_empty`.
	/// 
	/// Usually implemented as `!self.is_empty()`, but as that method
	/// is not defined by a Trait in stable Rust, this needs re-implementing
	/// for each type that requires it.
	/// 
	/// # Examples
	/// ```
	/// use has_some::HasSome;
	/// 
	/// assert!("this is not empty".has_some());
	/// ```
	/// 
	/// ```
	/// use has_some::HasSome;
	/// let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
	/// 
	/// let not_empties: Vec<String> = vector.into_iter().filter(String::has_some).collect();
	/// 
	/// assert_eq!(["some_data","more data"], not_empties.as_slice());
	/// ```
	fn has_some(&self) -> bool;

	/// `is_empty` in a form that is suitable for use in `Iterator::filter` where
	/// `Item = &OwnedType` (e.g. `&String`)
	/// 
	/// # Examples
	/// 
	/// ```
	/// use has_some::HasSome;
	/// let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
	/// 
	/// let empties: Vec<&String> = vector.iter().filter(String::is_empty2).collect();
	/// 
	/// assert_eq!([""], empties.as_slice());
	/// ```
	fn is_empty2(self: &&Self) -> bool;

	/// `is_empty` in a form that is suitable for use in `Iterator::filter` where
	/// `Item = &RefType` (e.g. `&&str`)
	/// 
	/// # Examples
	/// 
	/// ```
	/// use has_some::HasSome;
	/// let vector = vec!["some_data", "", "more data"];
	/// 
	/// let empties: Vec<&&str> = vector.iter().filter(str::is_empty3).collect();
	/// 
	/// assert_eq!([&""], empties.as_slice());
	/// ```
	fn is_empty3(self: &&&Self) -> bool {
		(*self).is_empty2()
	}

	/// `has_some` in a form that is suitable for use in `Iterator::filter` where
	/// `Item = &OwnedType` (e.g. `&String`)
	/// 
	/// # Examples
	/// 
	/// ```
	/// use has_some::HasSome;
	/// let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned()];
	/// 
	/// let not_empties: Vec<&String> = vector.iter().filter(String::has_some2).collect();
	/// 
	/// assert_eq!(["some_data","more data"], not_empties.as_slice());
	/// ```
	fn has_some2(self: &&Self) -> bool {
		(*self).has_some()
	}

	/// `has_some` in a form that is suitable for use in `Iterator::filter` where
	/// `Item = &RefType` (e.g. `&&str`)
	/// 
	/// # Examples
	/// 
	/// ```
	/// use has_some::HasSome;
	/// let vector = vec!["some_data", "", "more data"];
	/// 
	/// let not_empties: Vec<&&str> = vector.iter().filter(str::has_some3).collect();
	/// 
	/// assert_eq!([&"some_data", &"more data"], not_empties.as_slice());
	/// ```
	fn has_some3(self: &&&Self) -> bool {
		(*self).has_some()
	}
}
impl HasSome for str { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl HasSome for ::std::ffi::CStr { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl HasSome for ::std::string::String { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<Idx: PartialOrd<Idx>> HasSome for ::std::ops::Range<Idx> { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<Idx: PartialOrd<Idx>> HasSome for ::std::ops::RangeInclusive<Idx> { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<K,V,S: ::std::hash::BuildHasher> HasSome for ::std::collections::hash_map::HashMap<K,V,S> { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<K,V> HasSome for ::std::collections::BTreeMap<K,V> { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<T,S: ::std::hash::BuildHasher> HasSome for ::std::collections::hash_set::HashSet<T,S> { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<T> HasSome for [T] { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<T> HasSome for ::std::collections::BinaryHeap<T> { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<T> HasSome for ::std::collections::BTreeSet<T> { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<T> HasSome for ::std::collections::LinkedList<T> { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<T> HasSome for ::std::collections::VecDeque<T> { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }
impl<T> HasSome for ::std::vec::Vec<T> { fn has_some(&self) -> bool { !self.is_empty() } fn is_empty2(self: &&Self) -> bool { (*self).is_empty() } }

/// The rare case where `is_empty` consumes `self`.
pub trait HasSomeConsume {
	fn has_some(self) -> bool;
	fn is_empty1(&self) -> bool;
	fn has_some1(&self) -> bool;
}
impl<T> HasSomeConsume for ::std::ptr::NonNull<[T]> { fn has_some(self) -> bool { !self.is_empty() } fn is_empty1(&self) -> bool { (*self).is_empty() } fn has_some1(&self) -> bool { !(*self).is_empty() } }

//Used for proc macs
//impl HasSome for TokenStream { fn has_some(&self) -> bool { !self.is_empty() } }

//The issue #35428 is EIGHT years old at writing!!! - it will supersede all the above except the top two if it ever gets finalized
//impl<T: ExactSizeIterator> HasSome for T { fn has_some(&self) -> bool { !self.is_empty() } }

//The issue #76915 is FOUR years old at writing!!!
//impl<'a> HasSome for ::std::os::unix::net::SocketAncillary<'a> { fn has_some(&self) -> bool { !self.is_empty() } }

//The issue #76915 is only 11 months old years old at writing, though the last comment was 8 months ago
//impl HasSome for ::std::ffi::os_str::OsStr { fn has_some(&self) -> bool { !self.is_empty() } }

#[cfg(test)]
mod tests {
	#[test]
	fn test_owned_items() {
		use super::HasSome;
		let vector = vec!["some_data".to_owned(), "".to_owned(), "more data".to_owned(), "".to_owned()];
		let vector2 = vector.clone();
		// If you want the empties, get can do
		let empties = vector.into_iter().filter(String::is_empty).collect::<Vec<String>>();
		assert_eq!(["", ""], empties.as_slice());
		// But If you want the non-empties, get can do
		let non_empties = vector2.into_iter().filter(String::has_some).collect::<Vec<String>>();
		assert_eq!(["some_data", "more data"], non_empties.as_slice());
	}

	#[test]
	fn test_ref_items() {
		use super::HasSome;
		let vector = vec!["some_data", "", "more data", ""];
		let vector2 = vector.clone();
		// If you want the empties, get can do
		let empties = vector.into_iter().filter(str::is_empty2).collect::<Vec<&str>>();
		assert_eq!(["", ""], empties.as_slice());
		// But If you want the non-empties, get can do
		let non_empties = vector2.iter().filter(str::has_some3).collect::<Vec<&&str>>();
		assert_eq!([&"some_data", &"more data"], non_empties.as_slice());
	}
}