refinement_types/
empty.rs1use core::fmt;
4
5use thiserror::Error;
6
7use crate::static_str::StaticStr;
8use crate::{core::Predicate, logic::Not};
9
10pub trait HasEmpty {
12 fn empty(&self) -> bool;
14}
15
16#[derive(Debug, Error, Default)]
18#[error("received non-empty value")]
19pub struct NonEmptyError;
20
21impl NonEmptyError {
22 pub const fn new() -> Self {
24 Self
25 }
26}
27
28pub const VALUE: StaticStr = "empty value";
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
33pub struct IsEmpty;
34
35impl<T: HasEmpty + ?Sized> Predicate<T> for IsEmpty {
36 type Error = NonEmptyError;
37
38 fn check(value: &T) -> Result<(), Self::Error> {
39 if value.empty() {
40 Ok(())
41 } else {
42 Err(Self::Error::new())
43 }
44 }
45
46 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
47 formatter.write_str(VALUE)
48 }
49}
50
51pub type IsNonEmpty = Not<IsEmpty>;
53
54impl HasEmpty for str {
57 fn empty(&self) -> bool {
58 self.is_empty()
59 }
60}
61
62impl<T> HasEmpty for [T] {
63 fn empty(&self) -> bool {
64 self.is_empty()
65 }
66}
67
68impl<T: HasEmpty + ?Sized> HasEmpty for &T {
69 fn empty(&self) -> bool {
70 T::empty(self)
71 }
72}
73
74#[cfg(feature = "alloc")]
77use alloc::{boxed::Box, string::String, vec::Vec};
78
79#[cfg(any(feature = "alloc", feature = "std"))]
80impl<T: HasEmpty + ?Sized> HasEmpty for Box<T> {
81 fn empty(&self) -> bool {
82 T::empty(self)
83 }
84}
85
86#[cfg(any(feature = "alloc", feature = "std"))]
87impl HasEmpty for String {
88 fn empty(&self) -> bool {
89 self.is_empty()
90 }
91}
92
93#[cfg(any(feature = "alloc", feature = "std"))]
94impl<T> HasEmpty for Vec<T> {
95 fn empty(&self) -> bool {
96 self.is_empty()
97 }
98}
99
100#[cfg(feature = "alloc")]
103use alloc::borrow::{Cow, ToOwned};
104
105#[cfg(all(not(feature = "alloc"), feature = "std"))]
106use std::borrow::{Cow, ToOwned};
107
108#[cfg(any(feature = "alloc", feature = "std"))]
109impl<T: ToOwned + HasEmpty + ?Sized> HasEmpty for Cow<'_, T> {
110 fn empty(&self) -> bool {
111 T::empty(self)
112 }
113}
114
115#[cfg(feature = "alloc")]
118use alloc::rc::Rc;
119
120#[cfg(all(not(feature = "alloc"), feature = "std"))]
121use std::rc::Rc;
122
123#[cfg(any(feature = "alloc", feature = "std"))]
124impl<T: HasEmpty + ?Sized> HasEmpty for Rc<T> {
125 fn empty(&self) -> bool {
126 T::empty(self)
127 }
128}
129
130#[cfg(feature = "alloc")]
131use alloc::sync::Arc;
132
133#[cfg(all(not(feature = "alloc"), feature = "std"))]
134use std::sync::Arc;
135
136#[cfg(any(feature = "alloc", feature = "std"))]
137impl<T: HasEmpty + ?Sized> HasEmpty for Arc<T> {
138 fn empty(&self) -> bool {
139 T::empty(self)
140 }
141}
142
143#[cfg(feature = "alloc")]
146use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
147
148#[cfg(all(not(feature = "alloc"), feature = "std"))]
149use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
150
151#[cfg(any(feature = "alloc", feature = "std"))]
152impl<K, V> HasEmpty for BTreeMap<K, V> {
153 fn empty(&self) -> bool {
154 self.is_empty()
155 }
156}
157
158#[cfg(any(feature = "alloc", feature = "std"))]
159impl<T> HasEmpty for BTreeSet<T> {
160 fn empty(&self) -> bool {
161 self.is_empty()
162 }
163}
164
165#[cfg(any(feature = "alloc", feature = "std"))]
166impl<T> HasEmpty for BinaryHeap<T> {
167 fn empty(&self) -> bool {
168 self.is_empty()
169 }
170}
171
172#[cfg(any(feature = "alloc", feature = "std"))]
173impl<T> HasEmpty for LinkedList<T> {
174 fn empty(&self) -> bool {
175 self.is_empty()
176 }
177}
178
179#[cfg(any(feature = "alloc", feature = "std"))]
180impl<T> HasEmpty for VecDeque<T> {
181 fn empty(&self) -> bool {
182 self.is_empty()
183 }
184}
185
186#[cfg(feature = "std")]
189use std::collections::{HashMap, HashSet};
190
191#[cfg(feature = "std")]
192impl<K, V, S> HasEmpty for HashMap<K, V, S> {
193 fn empty(&self) -> bool {
194 self.is_empty()
195 }
196}
197
198#[cfg(feature = "std")]
199impl<T, S> HasEmpty for HashSet<T, S> {
200 fn empty(&self) -> bool {
201 self.is_empty()
202 }
203}
204
205#[cfg(feature = "std")]
208use std::ffi::{OsStr, OsString};
209
210#[cfg(feature = "std")]
211impl HasEmpty for OsStr {
212 fn empty(&self) -> bool {
213 self.is_empty()
214 }
215}
216
217#[cfg(feature = "std")]
218impl HasEmpty for OsString {
219 fn empty(&self) -> bool {
220 self.is_empty()
221 }
222}
223
224#[cfg(feature = "std")]
227use std::path::{Path, PathBuf};
228
229#[cfg(feature = "std")]
230impl HasEmpty for Path {
231 fn empty(&self) -> bool {
232 self.as_os_str().is_empty()
233 }
234}
235
236#[cfg(feature = "std")]
237impl HasEmpty for PathBuf {
238 fn empty(&self) -> bool {
239 self.as_os_str().is_empty()
240 }
241}