Skip to main content

refining_str/
predicates.rs

1//! Predicates for strings.
2
3use core::{fmt, marker::PhantomData};
4
5use refining_core::{
6    predicate::Predicate,
7    types::{StaticStr, TypeStr},
8};
9
10/// Checks if the string starts with the specified prefix `P`.
11pub struct StartsWith<P: TypeStr + ?Sized> {
12    prefix: PhantomData<P>,
13}
14
15impl<P: TypeStr + ?Sized> StartsWith<P> {
16    /// Returns the expected prefix.
17    #[must_use]
18    pub const fn prefix() -> StaticStr {
19        P::VALUE
20    }
21}
22
23/// The `str::starts_with` literal.
24pub const STARTS_WITH: &str = "str::starts_with";
25
26impl<T: AsRef<str> + ?Sized, P: TypeStr + ?Sized> Predicate<T> for StartsWith<P> {
27    fn check(value: &T) -> bool {
28        value.as_ref().starts_with(Self::prefix())
29    }
30
31    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
32        write!(
33            formatter,
34            "string starting with `{prefix}`",
35            prefix = Self::prefix()
36        )
37    }
38
39    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
40        formatter.write_str(STARTS_WITH)
41    }
42}
43
44/// Checks if the string ends with the specified suffix `S`.
45pub struct EndsWith<S: TypeStr + ?Sized> {
46    suffix: PhantomData<S>,
47}
48
49impl<S: TypeStr + ?Sized> EndsWith<S> {
50    /// Returns the expected suffix.
51    #[must_use]
52    pub const fn suffix() -> StaticStr {
53        S::VALUE
54    }
55}
56
57/// The `str::ends_with` literal.
58pub const ENDS_WITH: &str = "str::ends_with";
59
60impl<T: AsRef<str> + ?Sized, S: TypeStr + ?Sized> Predicate<T> for EndsWith<S> {
61    fn check(value: &T) -> bool {
62        value.as_ref().ends_with(Self::suffix())
63    }
64
65    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
66        write!(
67            formatter,
68            "string ending with `{suffix}`",
69            suffix = Self::suffix()
70        )
71    }
72
73    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
74        formatter.write_str(ENDS_WITH)
75    }
76}
77
78/// Checks if the string contains the specified string `S`.
79pub struct Contains<S: TypeStr + ?Sized> {
80    string: PhantomData<S>,
81}
82
83impl<S: TypeStr + ?Sized> Contains<S> {
84    /// Returns the expected string.
85    #[must_use]
86    pub const fn string() -> StaticStr {
87        S::VALUE
88    }
89}
90
91/// The `str::contains` literal.
92pub const CONTAINS: &str = "str::contains";
93
94impl<T: AsRef<str> + ?Sized, S: TypeStr + ?Sized> Predicate<T> for Contains<S> {
95    fn check(value: &T) -> bool {
96        value.as_ref().contains(Self::string())
97    }
98
99    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
100        write!(
101            formatter,
102            "string containing `{string}`",
103            string = Self::string()
104        )
105    }
106
107    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
108        formatter.write_str(CONTAINS)
109    }
110}
111
112/// Checks if the string starts with the specified character `C`.
113pub struct StartsWithChar<const C: char> {
114    private: PhantomData<()>,
115}
116
117impl<const C: char> StartsWithChar<C> {
118    /// Returns the expected character.
119    #[must_use]
120    pub const fn character() -> char {
121        C
122    }
123}
124
125impl<T: AsRef<str> + ?Sized, const C: char> Predicate<T> for StartsWithChar<C> {
126    fn check(value: &T) -> bool {
127        value.as_ref().starts_with(Self::character())
128    }
129
130    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
131        write!(
132            formatter,
133            "string starting with `{character}`",
134            character = Self::character()
135        )
136    }
137
138    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
139        write!(
140            formatter,
141            "str::starts_with<{character}>",
142            character = Self::character()
143        )
144    }
145}
146
147/// Checks if the string ends with the specified character `C`.
148pub struct EndsWithChar<const C: char> {
149    private: PhantomData<()>,
150}
151
152impl<const C: char> EndsWithChar<C> {
153    /// Returns the expected character.
154    #[must_use]
155    pub const fn character() -> char {
156        C
157    }
158}
159
160impl<T: AsRef<str> + ?Sized, const C: char> Predicate<T> for EndsWithChar<C> {
161    fn check(value: &T) -> bool {
162        value.as_ref().ends_with(Self::character())
163    }
164
165    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
166        write!(
167            formatter,
168            "string ending with `{character}`",
169            character = Self::character()
170        )
171    }
172
173    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
174        write!(
175            formatter,
176            "str::ends_with<{character}>",
177            character = Self::character()
178        )
179    }
180}
181
182/// Checks if the string contains the specified character `C`.
183pub struct ContainsChar<const C: char> {
184    private: PhantomData<()>,
185}
186
187impl<const C: char> ContainsChar<C> {
188    /// Returns the expected character.
189    #[must_use]
190    pub const fn character() -> char {
191        C
192    }
193}
194
195impl<T: AsRef<str> + ?Sized, const C: char> Predicate<T> for ContainsChar<C> {
196    fn check(value: &T) -> bool {
197        value.as_ref().contains(Self::character())
198    }
199
200    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
201        write!(
202            formatter,
203            "string containing `{character}`",
204            character = Self::character()
205        )
206    }
207
208    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
209        write!(
210            formatter,
211            "str::contains<{character}>",
212            character = Self::character()
213        )
214    }
215}
216
217/// Checks if the string is trimmed at the start.
218pub struct TrimmedStart {
219    private: PhantomData<()>,
220}
221
222/// The `string trimmed at the start` message.
223pub const TRIMMED_START_MESSAGE: &str = "string trimmed at the start";
224
225/// The `str::trimmed_start` literal.
226pub const TRIMMED_START: &str = "str::trimmed_start";
227
228impl<T: AsRef<str> + ?Sized> Predicate<T> for TrimmedStart {
229    fn check(value: &T) -> bool {
230        let string = value.as_ref();
231
232        string.trim_start() == string
233    }
234
235    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
236        formatter.write_str(TRIMMED_START_MESSAGE)
237    }
238
239    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
240        formatter.write_str(TRIMMED_START)
241    }
242}
243
244/// Checks if the string is trimmed at the end.
245pub struct TrimmedEnd {
246    private: PhantomData<()>,
247}
248
249/// The `string trimmed at the end` message.
250pub const TRIMMED_END_MESSAGE: &str = "string trimmed at the end";
251
252/// The `str::trimmed_end` literal.
253pub const TRIMMED_END: &str = "str::trimmed_end";
254
255impl<T: AsRef<str> + ?Sized> Predicate<T> for TrimmedEnd {
256    fn check(value: &T) -> bool {
257        let string = value.as_ref();
258
259        string.trim_end() == string
260    }
261
262    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
263        formatter.write_str(TRIMMED_END_MESSAGE)
264    }
265
266    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
267        formatter.write_str(TRIMMED_END)
268    }
269}
270
271/// Checks if the string is trimmed.
272pub struct Trimmed {
273    private: PhantomData<()>,
274}
275
276/// The `trimmed string` message.
277pub const TRIMMED_MESSAGE: &str = "trimmed string";
278
279/// The `str::trimmed` literal.
280pub const TRIMMED: &str = "str::trimmed";
281
282impl<T: AsRef<str> + ?Sized> Predicate<T> for Trimmed {
283    fn check(value: &T) -> bool {
284        let string = value.as_ref();
285
286        string.trim() == string
287    }
288
289    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
290        formatter.write_str(TRIMMED_MESSAGE)
291    }
292
293    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
294        formatter.write_str(TRIMMED)
295    }
296}
297
298/// Checks if the string is valid ASCII.
299pub struct Ascii {
300    private: PhantomData<()>,
301}
302
303/// The `ascii string` message.
304pub const ASCII_MESSAGE: &str = "ascii string";
305
306/// The `str::ascii` literal.
307pub const ASCII: &str = "str::ascii";
308
309impl<T: AsRef<str> + ?Sized> Predicate<T> for Ascii {
310    fn check(value: &T) -> bool {
311        value.as_ref().is_ascii()
312    }
313
314    fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
315        formatter.write_str(ASCII_MESSAGE)
316    }
317
318    fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
319        formatter.write_str(ASCII)
320    }
321}