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