Skip to main content

refining_length/
predicates.rs

1//! Predicates based on length.
2
3use core::{fmt, marker::PhantomData};
4
5use refining_core::{
6    logical::{And, Not},
7    predicate::Predicate,
8};
9
10use crate::length::HasLength;
11
12/// Checks whether the value has length equal to `N`.
13pub struct LengthEqual<const N: usize> {
14    private: PhantomData<()>,
15}
16
17impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for LengthEqual<N> {
18    fn check(value: &T) -> bool {
19        value.length() == N
20    }
21
22    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
23        write!(formatter, "value with length == {N}")
24    }
25
26    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
27        write!(formatter, "length::eq<{N}>")
28    }
29}
30
31/// Checks whether the value has length not equal to `N`.
32pub struct LengthNotEqual<const N: usize> {
33    private: PhantomData<()>,
34}
35
36impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for LengthNotEqual<N> {
37    fn check(value: &T) -> bool {
38        value.length() != N
39    }
40
41    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
42        write!(formatter, "value with length != {N}")
43    }
44
45    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
46        write!(formatter, "length::ne<{N}>")
47    }
48}
49
50/// Checks whether the value has length less than `N`.
51pub struct LengthLess<const N: usize> {
52    private: PhantomData<()>,
53}
54
55impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for LengthLess<N> {
56    fn check(value: &T) -> bool {
57        value.length() < N
58    }
59
60    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
61        write!(formatter, "value with length < {N}")
62    }
63
64    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
65        write!(formatter, "length::lt<{N}>")
66    }
67}
68
69/// Checks whether the value has length greater than `N`.
70pub struct LengthGreater<const N: usize> {
71    private: PhantomData<()>,
72}
73
74impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for LengthGreater<N> {
75    fn check(value: &T) -> bool {
76        value.length() > N
77    }
78
79    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
80        write!(formatter, "value with length > {N}")
81    }
82
83    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
84        write!(formatter, "length::gt<{N}>")
85    }
86}
87
88/// Checks whether the value has length less than or equal to `N`.
89pub struct LengthLessOrEqual<const N: usize> {
90    private: PhantomData<()>,
91}
92
93impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for LengthLessOrEqual<N> {
94    fn check(value: &T) -> bool {
95        value.length() <= N
96    }
97
98    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
99        write!(formatter, "value with length <= {N}")
100    }
101
102    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
103        write!(formatter, "length::le<{N}>")
104    }
105}
106
107/// Checks whether the value has length greater than or equal to `N`.
108pub struct LengthGreaterOrEqual<const N: usize> {
109    private: PhantomData<()>,
110}
111
112impl<const N: usize, T: HasLength + ?Sized> Predicate<T> for LengthGreaterOrEqual<N> {
113    fn check(value: &T) -> bool {
114        value.length() >= N
115    }
116
117    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
118        write!(formatter, "value with length >= {N}")
119    }
120
121    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
122        write!(formatter, "length::ge<{N}>")
123    }
124}
125
126/// Represents `(M, N)` intervals.
127pub type LengthOpen<const M: usize, const N: usize> = And<LengthGreater<M>, LengthLess<N>>;
128
129/// Represents `[M, N)` intervals.
130pub type LengthClosedOpen<const M: usize, const N: usize> =
131    And<LengthGreaterOrEqual<M>, LengthLess<N>>;
132
133/// Represents `(M, N]` intervals.
134pub type LengthOpenClosed<const M: usize, const N: usize> =
135    And<LengthGreater<M>, LengthLessOrEqual<N>>;
136
137/// Represents `[M, N]` intervals.
138pub type LengthClosed<const M: usize, const N: usize> =
139    And<LengthGreaterOrEqual<M>, LengthLessOrEqual<N>>;
140
141/// Zero (`0`) length.
142pub const ZERO: usize = 0;
143
144/// Checks whether the given value has zero length.
145pub type LengthZero = LengthEqual<ZERO>;
146
147/// Checks whether the given value has non-zero length.
148pub type LengthNonZero = LengthNotEqual<ZERO>;
149
150/// Checks whether the given value has length that has modulo `M` when divided by `D`.
151pub struct LengthModulo<const D: usize, const M: usize> {
152    private: PhantomData<()>,
153}
154
155impl<const D: usize, const M: usize, T: HasLength + ?Sized> Predicate<T> for LengthModulo<D, M> {
156    fn check(value: &T) -> bool {
157        value.length() % D == M
158    }
159
160    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
161        write!(formatter, "value with length % {D} == {M}")
162    }
163
164    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
165        write!(formatter, "length::mod<{D}, {M}>")
166    }
167}
168
169/// Checks whether the given value length is divisible by `D`.
170pub type LengthDivisible<const D: usize> = LengthModulo<D, ZERO>;
171
172/// Two (`2`) length.
173pub const TWO: usize = 2;
174
175/// Checks whether the given value length is even.
176pub type LengthEven = LengthDivisible<TWO>;
177
178/// Checks whether the given value length is odd.
179pub type LengthOdd = Not<LengthEven>;