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