1use core::fmt;
4
5#[cfg(feature = "diagnostics")]
6use miette::Diagnostic;
7
8use thiserror::Error;
9
10use crate::{
11 core::Predicate,
12 logic::{And, Not},
13};
14
15pub trait HasLength {
17 fn length(&self) -> usize;
19}
20
21#[derive(Debug, Error)]
24#[error("received value with length >= {other}")]
25#[cfg_attr(
26 feature = "diagnostics",
27 derive(Diagnostic),
28 diagnostic(code(length::lt), help("make sure the length is less than {other}"))
29)]
30pub struct LessError {
31 pub other: usize,
33}
34
35impl LessError {
36 pub const fn new(other: usize) -> Self {
38 Self { other }
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
44pub struct Less<const N: usize>;
45
46impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Less<N> {
47 type Error = LessError;
48
49 fn check(value: &T) -> Result<(), Self::Error> {
50 if value.length() < N {
51 Ok(())
52 } else {
53 Err(Self::Error::new(N))
54 }
55 }
56
57 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
58 write!(formatter, "value with length < {N}")
59 }
60
61 fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
62 write!(formatter, "length::lt<{N}>")
63 }
64}
65
66#[derive(Debug, Error)]
69#[error("received value with length > {other}")]
70#[cfg_attr(
71 feature = "diagnostics",
72 derive(Diagnostic),
73 diagnostic(
74 code(length::le),
75 help("make sure the length is less than or equal to {other}")
76 )
77)]
78pub struct LessOrEqualError {
79 pub other: usize,
81}
82
83impl LessOrEqualError {
84 pub const fn new(other: usize) -> Self {
86 Self { other }
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
92pub struct LessOrEqual<const N: usize>;
93
94impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for LessOrEqual<N> {
95 type Error = LessOrEqualError;
96
97 fn check(value: &T) -> Result<(), Self::Error> {
98 if value.length() <= N {
99 Ok(())
100 } else {
101 Err(Self::Error::new(N))
102 }
103 }
104
105 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(formatter, "value with length <= {N}")
107 }
108
109 fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
110 write!(formatter, "length::le<{N}>")
111 }
112}
113
114#[derive(Debug, Error)]
117#[error("received value with length <= {other}")]
118#[cfg_attr(
119 feature = "diagnostics",
120 derive(Diagnostic),
121 diagnostic(code(length::gt), help("make sure the length is greater than {other}"))
122)]
123pub struct GreaterError {
124 pub other: usize,
126}
127
128impl GreaterError {
129 pub const fn new(other: usize) -> Self {
131 Self { other }
132 }
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
137pub struct Greater<const N: usize>;
138
139impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Greater<N> {
140 type Error = GreaterError;
141
142 fn check(value: &T) -> Result<(), Self::Error> {
143 if value.length() > N {
144 Ok(())
145 } else {
146 Err(Self::Error::new(N))
147 }
148 }
149
150 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
151 write!(formatter, "value with length > {N}")
152 }
153
154 fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
155 write!(formatter, "length::gt<{N}>")
156 }
157}
158
159#[derive(Debug, Error)]
162#[error("received value with length < {other}")]
163#[cfg_attr(
164 feature = "diagnostics",
165 derive(Diagnostic),
166 diagnostic(
167 code(length::ge),
168 help("make sure the length is greater than or equal to {other}")
169 )
170)]
171pub struct GreaterOrEqualError {
172 pub other: usize,
174}
175
176impl GreaterOrEqualError {
177 pub const fn new(other: usize) -> Self {
179 Self { other }
180 }
181}
182
183#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
185pub struct GreaterOrEqual<const N: usize>;
186
187impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for GreaterOrEqual<N> {
188 type Error = GreaterOrEqualError;
189
190 fn check(value: &T) -> Result<(), Self::Error> {
191 if value.length() >= N {
192 Ok(())
193 } else {
194 Err(Self::Error::new(N))
195 }
196 }
197
198 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
199 write!(formatter, "value with length >= {N}")
200 }
201
202 fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
203 write!(formatter, "length::ge<{N}>")
204 }
205}
206
207#[derive(Debug, Error)]
210#[error("received value with length != {other}")]
211#[cfg_attr(
212 feature = "diagnostics",
213 derive(Diagnostic),
214 diagnostic(code(length::eq), help("make sure the length is equal to {other}"))
215)]
216pub struct EqualError {
217 pub other: usize,
219}
220
221impl EqualError {
222 pub const fn new(other: usize) -> Self {
224 Self { other }
225 }
226}
227
228#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
230pub struct Equal<const N: usize>;
231
232impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for Equal<N> {
233 type Error = EqualError;
234
235 fn check(value: &T) -> Result<(), Self::Error> {
236 if value.length() == N {
237 Ok(())
238 } else {
239 Err(Self::Error::new(N))
240 }
241 }
242
243 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
244 write!(formatter, "value with length == {N}")
245 }
246
247 fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
248 write!(formatter, "length::eq<{N}>")
249 }
250}
251
252#[derive(Debug, Error)]
255#[error("received value with length == {other}")]
256#[cfg_attr(
257 feature = "diagnostics",
258 derive(Diagnostic),
259 diagnostic(code(length::ne), help("make sure the length is not equal to {other}"))
260)]
261pub struct NotEqualError {
262 pub other: usize,
264}
265
266impl NotEqualError {
267 pub const fn new(other: usize) -> Self {
269 Self { other }
270 }
271}
272
273#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
275pub struct NotEqual<const N: usize>;
276
277impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for NotEqual<N> {
278 type Error = NotEqualError;
279
280 #[allow(clippy::if_not_else)]
281 fn check(value: &T) -> Result<(), Self::Error> {
282 if value.length() != N {
283 Ok(())
284 } else {
285 Err(Self::Error::new(N))
286 }
287 }
288
289 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
290 write!(formatter, "value with length != {N}")
291 }
292
293 fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
294 write!(formatter, "length::ne<{N}>")
295 }
296}
297
298pub type Open<const M: usize, const N: usize> = And<Greater<M>, Less<N>>;
300
301pub type ClosedOpen<const M: usize, const N: usize> = And<GreaterOrEqual<M>, Less<N>>;
303
304pub type OpenClosed<const M: usize, const N: usize> = And<Greater<M>, LessOrEqual<N>>;
306
307pub type Closed<const M: usize, const N: usize> = And<GreaterOrEqual<M>, LessOrEqual<N>>;
309
310pub type Zero = Equal<0>;
312
313pub type NonZero = NotEqual<0>;
315
316#[derive(Debug, Error)]
322#[error("received value % {divisor} != {modulo}")]
323pub struct ModuloError {
324 pub divisor: usize,
326 pub modulo: usize,
328}
329
330impl ModuloError {
331 pub const fn new(divisor: usize, modulo: usize) -> Self {
333 Self { divisor, modulo }
334 }
335}
336
337#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
339pub struct Modulo<const D: usize, const M: usize>;
340
341impl<const D: usize, const M: usize, T: HasLength + ?Sized> Predicate<T> for Modulo<D, M> {
342 type Error = ModuloError;
343
344 fn check(value: &T) -> Result<(), Self::Error> {
345 if value.length() % D == M {
346 Ok(())
347 } else {
348 Err(Self::Error::new(D, M))
349 }
350 }
351
352 fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
353 write!(formatter, "length % {D} == {M}")
354 }
355
356 fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
357 write!(formatter, "length::mod<{D}, {M}>")
358 }
359}
360
361pub type Divisible<const D: usize> = Modulo<D, 0>;
363
364pub type Even = Divisible<2>;
366
367pub type Odd = Not<Even>;
369
370impl HasLength for str {
373 fn length(&self) -> usize {
374 self.len()
375 }
376}
377
378impl<T> HasLength for [T] {
379 fn length(&self) -> usize {
380 self.len()
381 }
382}
383
384impl<T: HasLength + ?Sized> HasLength for &T {
385 fn length(&self) -> usize {
386 T::length(self)
387 }
388}
389
390#[cfg(feature = "alloc")]
393use alloc::{boxed::Box, string::String, vec::Vec};
394
395#[cfg(any(feature = "alloc", feature = "std"))]
396impl<T: HasLength + ?Sized> HasLength for Box<T> {
397 fn length(&self) -> usize {
398 T::length(self)
399 }
400}
401
402#[cfg(any(feature = "alloc", feature = "std"))]
403impl HasLength for String {
404 fn length(&self) -> usize {
405 self.len()
406 }
407}
408
409#[cfg(any(feature = "alloc", feature = "std"))]
410impl<T> HasLength for Vec<T> {
411 fn length(&self) -> usize {
412 self.len()
413 }
414}
415
416#[cfg(feature = "alloc")]
419use alloc::borrow::{Cow, ToOwned};
420
421#[cfg(all(not(feature = "alloc"), feature = "std"))]
422use std::borrow::{Cow, ToOwned};
423
424#[cfg(any(feature = "alloc", feature = "std"))]
425impl<T: ToOwned + HasLength + ?Sized> HasLength for Cow<'_, T> {
426 fn length(&self) -> usize {
427 T::length(self)
428 }
429}
430
431#[cfg(feature = "alloc")]
434use alloc::rc::Rc;
435
436#[cfg(all(not(feature = "alloc"), feature = "std"))]
437use std::rc::Rc;
438
439#[cfg(any(feature = "alloc", feature = "std"))]
440impl<T: HasLength + ?Sized> HasLength for Rc<T> {
441 fn length(&self) -> usize {
442 T::length(self)
443 }
444}
445
446#[cfg(feature = "alloc")]
447use alloc::sync::Arc;
448
449#[cfg(all(not(feature = "alloc"), feature = "std"))]
450use std::sync::Arc;
451
452#[cfg(any(feature = "alloc", feature = "std"))]
453impl<T: HasLength + ?Sized> HasLength for Arc<T> {
454 fn length(&self) -> usize {
455 T::length(self)
456 }
457}
458
459#[cfg(feature = "alloc")]
462use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
463
464#[cfg(all(not(feature = "alloc"), feature = "std"))]
465use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
466
467#[cfg(any(feature = "alloc", feature = "std"))]
468impl<K, V> HasLength for BTreeMap<K, V> {
469 fn length(&self) -> usize {
470 self.len()
471 }
472}
473
474#[cfg(any(feature = "alloc", feature = "std"))]
475impl<T> HasLength for BTreeSet<T> {
476 fn length(&self) -> usize {
477 self.len()
478 }
479}
480
481#[cfg(any(feature = "alloc", feature = "std"))]
482impl<T> HasLength for BinaryHeap<T> {
483 fn length(&self) -> usize {
484 self.len()
485 }
486}
487
488#[cfg(any(feature = "alloc", feature = "std"))]
489impl<T> HasLength for LinkedList<T> {
490 fn length(&self) -> usize {
491 self.len()
492 }
493}
494
495#[cfg(any(feature = "alloc", feature = "std"))]
496impl<T> HasLength for VecDeque<T> {
497 fn length(&self) -> usize {
498 self.len()
499 }
500}
501
502#[cfg(feature = "std")]
505use std::collections::{HashMap, HashSet};
506
507#[cfg(feature = "std")]
508impl<K, V, S> HasLength for HashMap<K, V, S> {
509 fn length(&self) -> usize {
510 self.len()
511 }
512}
513
514#[cfg(feature = "std")]
515impl<T, S> HasLength for HashSet<T, S> {
516 fn length(&self) -> usize {
517 self.len()
518 }
519}
520
521#[cfg(feature = "std")]
524use std::ffi::{OsStr, OsString};
525
526#[cfg(feature = "std")]
527impl HasLength for OsStr {
528 fn length(&self) -> usize {
529 self.len()
530 }
531}
532
533#[cfg(feature = "std")]
534impl HasLength for OsString {
535 fn length(&self) -> usize {
536 self.len()
537 }
538}
539
540#[cfg(feature = "std")]
543use std::path::{Path, PathBuf};
544
545#[cfg(feature = "std")]
546impl HasLength for Path {
547 fn length(&self) -> usize {
548 self.as_os_str().length()
549 }
550}
551
552#[cfg(feature = "std")]
553impl HasLength for PathBuf {
554 fn length(&self) -> usize {
555 self.as_os_str().length()
556 }
557}