refined/
character.rs

1//! [char] refinement.
2//!
3//! # Example
4//!
5//! ```
6//! use refined::{Refinement, RefinementOps, character::IsDigit};
7//!
8//! type Test = Refinement<char, IsDigit>;
9//!
10//! assert!(Test::refine('0').is_ok());
11//! assert!(Test::refine('a').is_err());
12//! ```
13use crate::{ErrorMessage, Predicate};
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
16pub struct IsControl;
17
18impl Predicate<char> for IsControl {
19    fn test(value: &char) -> bool {
20        value.is_control()
21    }
22
23    #[cfg(feature = "alloc")]
24    fn error() -> ErrorMessage {
25        ErrorMessage::from("must be a control character")
26    }
27
28    #[cfg(not(feature = "alloc"))]
29    fn error() -> ErrorMessage {
30        "must be a control character"
31    }
32
33    unsafe fn optimize(value: &char) {
34        core::hint::assert_unchecked(Self::test(value));
35    }
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
39pub struct IsDigit;
40
41impl Predicate<char> for IsDigit {
42    fn test(value: &char) -> bool {
43        value.is_ascii_digit()
44    }
45
46    #[cfg(feature = "alloc")]
47    fn error() -> ErrorMessage {
48        ErrorMessage::from("must be a digit")
49    }
50
51    #[cfg(not(feature = "alloc"))]
52    fn error() -> ErrorMessage {
53        "must be a digit"
54    }
55
56    unsafe fn optimize(value: &char) {
57        core::hint::assert_unchecked(Self::test(value));
58    }
59}
60
61#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
62pub struct IsLowercase;
63
64impl Predicate<char> for IsLowercase {
65    fn test(value: &char) -> bool {
66        value.is_lowercase()
67    }
68
69    #[cfg(feature = "alloc")]
70    fn error() -> ErrorMessage {
71        ErrorMessage::from("must be a lowercase character")
72    }
73
74    #[cfg(not(feature = "alloc"))]
75    fn error() -> ErrorMessage {
76        "must be a lowercase character"
77    }
78
79    unsafe fn optimize(value: &char) {
80        core::hint::assert_unchecked(Self::test(value));
81    }
82}
83
84#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
85pub struct IsUppercase;
86
87impl Predicate<char> for IsUppercase {
88    fn test(value: &char) -> bool {
89        value.is_uppercase()
90    }
91
92    #[cfg(feature = "alloc")]
93    fn error() -> ErrorMessage {
94        ErrorMessage::from("must be an uppercase character")
95    }
96
97    #[cfg(not(feature = "alloc"))]
98    fn error() -> ErrorMessage {
99        "must be an uppercase character"
100    }
101
102    unsafe fn optimize(value: &char) {
103        core::hint::assert_unchecked(Self::test(value));
104    }
105}
106
107#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
108pub struct IsNumeric;
109
110impl Predicate<char> for IsNumeric {
111    fn test(value: &char) -> bool {
112        value.is_numeric()
113    }
114
115    #[cfg(feature = "alloc")]
116    fn error() -> ErrorMessage {
117        ErrorMessage::from("must be a numeric character")
118    }
119
120    #[cfg(not(feature = "alloc"))]
121    fn error() -> ErrorMessage {
122        "must be a numeric character"
123    }
124
125    unsafe fn optimize(value: &char) {
126        core::hint::assert_unchecked(Self::test(value));
127    }
128}
129
130#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
131pub struct IsWhitespace;
132
133impl Predicate<char> for IsWhitespace {
134    fn test(value: &char) -> bool {
135        value.is_whitespace()
136    }
137
138    #[cfg(feature = "alloc")]
139    fn error() -> ErrorMessage {
140        ErrorMessage::from("must be a whitespace character")
141    }
142
143    #[cfg(not(feature = "alloc"))]
144    fn error() -> ErrorMessage {
145        "must be a whitespace character"
146    }
147
148    unsafe fn optimize(value: &char) {
149        core::hint::assert_unchecked(Self::test(value));
150    }
151}
152
153#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
154pub struct IsHexDigit;
155
156impl Predicate<char> for IsHexDigit {
157    fn test(value: &char) -> bool {
158        value.is_ascii_hexdigit()
159    }
160
161    #[cfg(feature = "alloc")]
162    fn error() -> ErrorMessage {
163        ErrorMessage::from("must be a valid hex character")
164    }
165
166    #[cfg(not(feature = "alloc"))]
167    fn error() -> ErrorMessage {
168        "must be a valid hex character"
169    }
170
171    unsafe fn optimize(value: &char) {
172        core::hint::assert_unchecked(Self::test(value));
173    }
174}
175
176#[cfg(test)]
177mod tests {
178    use super::*;
179    use crate::*;
180
181    #[test]
182    fn test_is_control() {
183        type Test = Refinement<char, IsControl>;
184        assert!(Test::refine('\u{009C}').is_ok());
185        assert!(Test::refine('0').is_err());
186    }
187
188    #[test]
189    fn test_is_digit() {
190        type Test = Refinement<char, IsDigit>;
191        assert!(Test::refine('a').is_err());
192        assert!(Test::refine('0').is_ok());
193    }
194
195    #[test]
196    fn test_is_lowercase() {
197        type Test = Refinement<char, IsLowercase>;
198        assert!(Test::refine('A').is_err());
199        assert!(Test::refine('a').is_ok());
200    }
201
202    #[test]
203    fn test_is_uppercase() {
204        type Test = Refinement<char, IsUppercase>;
205        assert!(Test::refine('A').is_ok());
206        assert!(Test::refine('a').is_err());
207    }
208
209    #[test]
210    fn test_is_numeric() {
211        type Test = Refinement<char, IsNumeric>;
212        assert!(Test::refine('A').is_err());
213        assert!(Test::refine('0').is_ok());
214    }
215
216    #[test]
217    fn test_is_whitespace() {
218        type Test = Refinement<char, IsWhitespace>;
219        assert!(Test::refine(' ').is_ok());
220        assert!(Test::refine('a').is_err());
221    }
222
223    #[test]
224    fn test_is_hex_digit() {
225        type Test = Refinement<char, IsHexDigit>;
226        assert!(Test::refine('F').is_ok());
227        assert!(Test::refine('G').is_err());
228    }
229}