Skip to main content

refining_empty/
empty.rs

1//! Predicates based on emptiness.
2
3use core::{ffi::CStr, fmt, marker::PhantomData};
4
5use refining_core::{logical::Not, predicate::Predicate, types::StaticStr};
6
7/// Represents types that have emptiness-checking capabilities.
8pub trait HasEmpty {
9    /// Checks whether the value is empty.
10    fn empty(&self) -> bool;
11}
12
13/// The `empty value` literal.
14pub const VALUE: StaticStr = "empty value";
15
16/// The `empty` literal.
17pub const EMPTY: StaticStr = "empty";
18
19/// Checks whether the value is empty.
20pub struct Empty {
21    private: PhantomData<()>,
22}
23
24impl<T: HasEmpty + ?Sized> Predicate<T> for Empty {
25    fn check(value: &T) -> bool {
26        value.empty()
27    }
28
29    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
30        formatter.write_str(VALUE)
31    }
32
33    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
34        formatter.write_str(EMPTY)
35    }
36}
37
38/// Checks whether the value is non-empty.
39pub type NonEmpty = Not<Empty>;
40
41// core
42
43impl HasEmpty for str {
44    fn empty(&self) -> bool {
45        self.is_empty()
46    }
47}
48
49impl<T> HasEmpty for [T] {
50    fn empty(&self) -> bool {
51        self.is_empty()
52    }
53}
54
55impl<T: HasEmpty + ?Sized> HasEmpty for &T {
56    fn empty(&self) -> bool {
57        (*self).empty()
58    }
59}
60
61impl HasEmpty for CStr {
62    fn empty(&self) -> bool {
63        self.is_empty()
64    }
65}
66
67#[cfg(any(feature = "std", feature = "alloc"))]
68mod std_or_alloc {
69    cfg_select! {
70        feature = "std" => {
71            use std::{
72                borrow::{Cow, ToOwned},
73                collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
74                ffi::CString,
75                rc::Rc,
76                sync::Arc,
77            };
78        }
79        feature = "alloc" => {
80            use alloc::{
81                borrow::{Cow, ToOwned},
82                boxed::Box,
83                collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque},
84                ffi::CString,
85                rc::Rc,
86                string::String,
87                sync::Arc,
88                vec::Vec,
89            };
90        }
91    }
92
93    use super::HasEmpty;
94
95    // prelude
96
97    impl<T: HasEmpty + ?Sized> HasEmpty for Box<T> {
98        fn empty(&self) -> bool {
99            self.as_ref().empty()
100        }
101    }
102
103    impl HasEmpty for String {
104        fn empty(&self) -> bool {
105            self.is_empty()
106        }
107    }
108
109    impl<T> HasEmpty for Vec<T> {
110        fn empty(&self) -> bool {
111            self.is_empty()
112        }
113    }
114
115    // C strings
116
117    impl HasEmpty for CString {
118        fn empty(&self) -> bool {
119            self.is_empty()
120        }
121    }
122
123    // clone-on-write
124
125    impl<T: ToOwned + HasEmpty + ?Sized> HasEmpty for Cow<'_, T> {
126        fn empty(&self) -> bool {
127            self.as_ref().empty()
128        }
129    }
130
131    // reference-counted
132
133    impl<T: HasEmpty + ?Sized> HasEmpty for Rc<T> {
134        fn empty(&self) -> bool {
135            self.as_ref().empty()
136        }
137    }
138
139    impl<T: HasEmpty + ?Sized> HasEmpty for Arc<T> {
140        fn empty(&self) -> bool {
141            self.as_ref().empty()
142        }
143    }
144
145    // collections
146
147    impl<K, V> HasEmpty for BTreeMap<K, V> {
148        fn empty(&self) -> bool {
149            self.is_empty()
150        }
151    }
152
153    impl<T> HasEmpty for BTreeSet<T> {
154        fn empty(&self) -> bool {
155            self.is_empty()
156        }
157    }
158
159    impl<T> HasEmpty for BinaryHeap<T> {
160        fn empty(&self) -> bool {
161            self.is_empty()
162        }
163    }
164
165    impl<T> HasEmpty for LinkedList<T> {
166        fn empty(&self) -> bool {
167            self.is_empty()
168        }
169    }
170
171    impl<T> HasEmpty for VecDeque<T> {
172        fn empty(&self) -> bool {
173            self.is_empty()
174        }
175    }
176}
177
178#[cfg(feature = "std")]
179mod std_only {
180    use std::{
181        collections::{HashMap, HashSet},
182        ffi::{OsStr, OsString},
183        path::{Path, PathBuf},
184    };
185
186    use super::HasEmpty;
187
188    // collections
189
190    impl<K, V, S> HasEmpty for HashMap<K, V, S> {
191        fn empty(&self) -> bool {
192            self.is_empty()
193        }
194    }
195
196    impl<T, S> HasEmpty for HashSet<T, S> {
197        fn empty(&self) -> bool {
198            self.is_empty()
199        }
200    }
201
202    // OS strings
203
204    impl HasEmpty for OsStr {
205        fn empty(&self) -> bool {
206            self.is_empty()
207        }
208    }
209
210    impl HasEmpty for OsString {
211        fn empty(&self) -> bool {
212            self.is_empty()
213        }
214    }
215
216    // paths (via underlying strings)
217
218    impl HasEmpty for Path {
219        fn empty(&self) -> bool {
220            self.as_os_str().empty()
221        }
222    }
223
224    impl HasEmpty for PathBuf {
225        fn empty(&self) -> bool {
226            self.as_os_str().empty()
227        }
228    }
229}