1use core::fmt;
4
5use thiserror::Error;
6
7use crate::{
8 core::Predicate,
9 logic::{And, Not},
10};
11
12pub trait HasLength {
14 fn length(&self) -> usize;
16}
17
18#[derive(Debug, Error)]
21#[error("received value with length >= {against}")]
22pub struct LtError {
23 pub against: usize,
25}
26
27impl LtError {
28 pub const fn new(against: usize) -> Self {
30 Self { against }
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
36pub struct Lt<const N: usize>;
37
38impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Lt<N> {
39 type Error = LtError;
40
41 fn check(value: &T) -> Result<(), Self::Error> {
42 if value.length() < N {
43 Ok(())
44 } else {
45 Err(Self::Error::new(N))
46 }
47 }
48
49 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
50 write!(formatter, "value with length < {N}")
51 }
52}
53
54#[derive(Debug, Error)]
57#[error("received value with length > {against}")]
58pub struct LeError {
59 pub against: usize,
61}
62
63impl LeError {
64 pub const fn new(against: usize) -> Self {
66 Self { against }
67 }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
72pub struct Le<const N: usize>;
73
74impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Le<N> {
75 type Error = LeError;
76
77 fn check(value: &T) -> Result<(), Self::Error> {
78 if value.length() <= N {
79 Ok(())
80 } else {
81 Err(Self::Error::new(N))
82 }
83 }
84
85 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
86 write!(formatter, "value with length <= {N}")
87 }
88}
89
90#[derive(Debug, Error)]
93#[error("received value with length <= {against}")]
94pub struct GtError {
95 pub against: usize,
97}
98
99impl GtError {
100 pub const fn new(against: usize) -> Self {
102 Self { against }
103 }
104}
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
108pub struct Gt<const N: usize>;
109
110impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Gt<N> {
111 type Error = GtError;
112
113 fn check(value: &T) -> Result<(), Self::Error> {
114 if value.length() > N {
115 Ok(())
116 } else {
117 Err(Self::Error::new(N))
118 }
119 }
120
121 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
122 write!(formatter, "value with length > {N}")
123 }
124}
125
126#[derive(Debug, Error)]
129#[error("received value with length < {against}")]
130pub struct GeError {
131 pub against: usize,
133}
134
135impl GeError {
136 pub const fn new(against: usize) -> Self {
138 Self { against }
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
144pub struct Ge<const N: usize>;
145
146impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Ge<N> {
147 type Error = GeError;
148
149 fn check(value: &T) -> Result<(), Self::Error> {
150 if value.length() >= N {
151 Ok(())
152 } else {
153 Err(Self::Error::new(N))
154 }
155 }
156
157 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
158 write!(formatter, "value with length >= {N}")
159 }
160}
161
162#[derive(Debug, Error)]
165#[error("received value with length != {against}")]
166pub struct EqError {
167 pub against: usize,
169}
170
171impl EqError {
172 pub const fn new(against: usize) -> Self {
174 Self { against }
175 }
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
180pub struct Eq<const N: usize>;
181
182impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Eq<N> {
183 type Error = EqError;
184
185 fn check(value: &T) -> Result<(), Self::Error> {
186 if value.length() == N {
187 Ok(())
188 } else {
189 Err(Self::Error::new(N))
190 }
191 }
192
193 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
194 write!(formatter, "value with length == {N}")
195 }
196}
197
198#[derive(Debug, Error)]
201#[error("received value with length == {against}")]
202pub struct NeError {
203 pub against: usize,
205}
206
207impl NeError {
208 pub const fn new(against: usize) -> Self {
210 Self { against }
211 }
212}
213
214#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
216pub struct Ne<const N: usize>;
217
218impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Ne<N> {
219 type Error = NeError;
220
221 #[allow(clippy::if_not_else)]
222 fn check(value: &T) -> Result<(), Self::Error> {
223 if value.length() != N {
224 Ok(())
225 } else {
226 Err(Self::Error::new(N))
227 }
228 }
229
230 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
231 write!(formatter, "value with length != {N}")
232 }
233}
234
235pub type Open<const M: usize, const N: usize> = And<Gt<M>, Lt<N>>;
237
238pub type ClosedOpen<const M: usize, const N: usize> = And<Ge<M>, Lt<N>>;
240
241pub type OpenClosed<const M: usize, const N: usize> = And<Gt<M>, Le<N>>;
243
244pub type Closed<const M: usize, const N: usize> = And<Ge<M>, Le<N>>;
246
247pub type Zero = Eq<0>;
249
250pub type NonZero = Ne<0>;
252
253#[derive(Debug, Error)]
259#[error("received value % {divisor} != {modulo}")]
260pub struct ModError {
261 pub divisor: usize,
263 pub modulo: usize,
265}
266
267impl ModError {
268 pub const fn new(divisor: usize, modulo: usize) -> Self {
270 Self { divisor, modulo }
271 }
272}
273
274#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
276pub struct Mod<const D: usize, const M: usize>;
277
278impl<const D: usize, const M: usize, T: HasLength + ?Sized> Predicate<T> for Mod<D, M> {
279 type Error = ModError;
280
281 fn check(value: &T) -> Result<(), Self::Error> {
282 if value.length() % D == M {
283 Ok(())
284 } else {
285 Err(Self::Error::new(D, M))
286 }
287 }
288
289 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
290 write!(formatter, "length % {D} == {M}")
291 }
292}
293
294pub type Div<const D: usize> = Mod<D, 0>;
296
297pub type Even = Div<2>;
299
300pub type Odd = Not<Even>;
302
303impl HasLength for str {
306 fn length(&self) -> usize {
307 self.len()
308 }
309}
310
311impl<T> HasLength for [T] {
312 fn length(&self) -> usize {
313 self.len()
314 }
315}
316
317impl<T: HasLength + ?Sized> HasLength for &T {
318 fn length(&self) -> usize {
319 T::length(self)
320 }
321}
322
323#[cfg(feature = "alloc")]
326use alloc::{boxed::Box, string::String, vec::Vec};
327
328#[cfg(any(feature = "alloc", feature = "std"))]
329impl<T: HasLength + ?Sized> HasLength for Box<T> {
330 fn length(&self) -> usize {
331 T::length(self)
332 }
333}
334
335#[cfg(any(feature = "alloc", feature = "std"))]
336impl HasLength for String {
337 fn length(&self) -> usize {
338 self.len()
339 }
340}
341
342#[cfg(any(feature = "alloc", feature = "std"))]
343impl<T> HasLength for Vec<T> {
344 fn length(&self) -> usize {
345 self.len()
346 }
347}
348
349#[cfg(feature = "alloc")]
352use alloc::borrow::{Cow, ToOwned};
353
354#[cfg(all(not(feature = "alloc"), feature = "std"))]
355use std::borrow::{Cow, ToOwned};
356
357#[cfg(any(feature = "alloc", feature = "std"))]
358impl<T: ToOwned + HasLength + ?Sized> HasLength for Cow<'_, T> {
359 fn length(&self) -> usize {
360 T::length(self)
361 }
362}
363
364#[cfg(feature = "alloc")]
367use alloc::rc::Rc;
368
369#[cfg(all(not(feature = "alloc"), feature = "std"))]
370use std::rc::Rc;
371
372#[cfg(any(feature = "alloc", feature = "std"))]
373impl<T: HasLength + ?Sized> HasLength for Rc<T> {
374 fn length(&self) -> usize {
375 T::length(self)
376 }
377}
378
379#[cfg(feature = "alloc")]
380use alloc::sync::Arc;
381
382#[cfg(all(not(feature = "alloc"), feature = "std"))]
383use std::sync::Arc;
384
385#[cfg(any(feature = "alloc", feature = "std"))]
386impl<T: HasLength + ?Sized> HasLength for Arc<T> {
387 fn length(&self) -> usize {
388 T::length(self)
389 }
390}
391
392#[cfg(feature = "alloc")]
395use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
396
397#[cfg(all(not(feature = "alloc"), feature = "std"))]
398use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
399
400#[cfg(any(feature = "alloc", feature = "std"))]
401impl<K, V> HasLength for BTreeMap<K, V> {
402 fn length(&self) -> usize {
403 self.len()
404 }
405}
406
407#[cfg(any(feature = "alloc", feature = "std"))]
408impl<T> HasLength for BTreeSet<T> {
409 fn length(&self) -> usize {
410 self.len()
411 }
412}
413
414#[cfg(any(feature = "alloc", feature = "std"))]
415impl<T> HasLength for BinaryHeap<T> {
416 fn length(&self) -> usize {
417 self.len()
418 }
419}
420
421#[cfg(any(feature = "alloc", feature = "std"))]
422impl<T> HasLength for LinkedList<T> {
423 fn length(&self) -> usize {
424 self.len()
425 }
426}
427
428#[cfg(any(feature = "alloc", feature = "std"))]
429impl<T> HasLength for VecDeque<T> {
430 fn length(&self) -> usize {
431 self.len()
432 }
433}
434
435#[cfg(feature = "std")]
438use std::collections::{HashMap, HashSet};
439
440#[cfg(feature = "std")]
441impl<K, V, S> HasLength for HashMap<K, V, S> {
442 fn length(&self) -> usize {
443 self.len()
444 }
445}
446
447#[cfg(feature = "std")]
448impl<T, S> HasLength for HashSet<T, S> {
449 fn length(&self) -> usize {
450 self.len()
451 }
452}
453
454#[cfg(feature = "std")]
457use std::ffi::{OsStr, OsString};
458
459#[cfg(feature = "std")]
460impl HasLength for OsStr {
461 fn length(&self) -> usize {
462 self.len()
463 }
464}
465
466#[cfg(feature = "std")]
467impl HasLength for OsString {
468 fn length(&self) -> usize {
469 self.len()
470 }
471}
472
473#[cfg(feature = "std")]
476use std::path::{Path, PathBuf};
477
478#[cfg(feature = "std")]
479impl HasLength for Path {
480 fn length(&self) -> usize {
481 self.as_os_str().length()
482 }
483}
484
485#[cfg(feature = "std")]
486impl HasLength for PathBuf {
487 fn length(&self) -> usize {
488 self.as_os_str().length()
489 }
490}