copybook_corruption_predicates/
lib.rs1#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used))]
2#[inline]
8#[must_use = "This predicate should be used intentionally in byte-level checks"]
9pub const fn is_ascii_printable(byte: u8) -> bool {
10 byte >= 0x20 && byte <= 0x7E
11}
12
13#[inline]
19#[must_use = "This predicate should be used intentionally in byte-level checks"]
20pub const fn is_likely_corrupted_ebcdic_byte(byte: u8) -> bool {
21 matches!(byte, 0x00..=0x1F | 0x7F..=0x9F)
22}
23
24#[inline]
26#[must_use = "This predicate should be used intentionally in packed-decimal checks"]
27pub const fn is_invalid_comp3_high_nibble(byte: u8) -> bool {
28 matches!((byte >> 4) & 0x0F, 0xA | 0xB | 0xE)
29}
30
31#[inline]
34#[must_use = "This predicate should be used intentionally in packed-decimal checks"]
35pub const fn is_invalid_comp3_low_nibble(byte: u8) -> bool {
36 matches!(byte & 0x0F, 0xA | 0xB | 0xE)
37}
38
39#[inline]
41#[must_use = "This predicate should be used intentionally in packed-decimal checks"]
42pub const fn is_invalid_comp3_sign_nibble(byte: u8) -> bool {
43 matches!(byte & 0x0F, 0x0..=0x9)
44}
45
46#[cfg(test)]
47#[allow(clippy::expect_used, clippy::unwrap_used)]
48mod tests {
49 use super::*;
50
51 #[test]
54 fn ascii_printable_examples() {
55 assert!(is_ascii_printable(b'A'));
56 assert!(is_ascii_printable(b' '));
57 assert!(!is_ascii_printable(0x1F));
58 }
59
60 #[test]
61 fn ascii_printable_lower_boundary() {
62 assert!(!is_ascii_printable(0x1F)); assert!(is_ascii_printable(0x20)); }
65
66 #[test]
67 fn ascii_printable_upper_boundary() {
68 assert!(is_ascii_printable(0x7E)); assert!(!is_ascii_printable(0x7F)); }
71
72 #[test]
73 fn ascii_printable_all_digits() {
74 for b in b'0'..=b'9' {
75 assert!(is_ascii_printable(b));
76 }
77 }
78
79 #[test]
80 fn ascii_printable_all_uppercase() {
81 for b in b'A'..=b'Z' {
82 assert!(is_ascii_printable(b));
83 }
84 }
85
86 #[test]
87 fn ascii_printable_null_and_max() {
88 assert!(!is_ascii_printable(0x00));
89 assert!(!is_ascii_printable(0xFF));
90 }
91
92 #[test]
95 fn likely_corrupted_ebcdic_examples() {
96 assert!(is_likely_corrupted_ebcdic_byte(0x00));
97 assert!(is_likely_corrupted_ebcdic_byte(0x7F));
98 assert!(!is_likely_corrupted_ebcdic_byte(b'A'));
99 assert!(!is_likely_corrupted_ebcdic_byte(0xFF));
100 }
101
102 #[test]
103 fn ebcdic_c0_range_all_corrupted() {
104 for b in 0x00..=0x1F {
105 assert!(
106 is_likely_corrupted_ebcdic_byte(b),
107 "byte 0x{b:02X} should be corrupted"
108 );
109 }
110 }
111
112 #[test]
113 fn ebcdic_c1_range_all_corrupted() {
114 for b in 0x7F..=0x9F {
115 assert!(
116 is_likely_corrupted_ebcdic_byte(b),
117 "byte 0x{b:02X} should be corrupted"
118 );
119 }
120 }
121
122 #[test]
123 fn ebcdic_boundary_0x20_not_corrupted() {
124 assert!(!is_likely_corrupted_ebcdic_byte(0x20));
125 }
126
127 #[test]
128 fn ebcdic_boundary_0xa0_not_corrupted() {
129 assert!(!is_likely_corrupted_ebcdic_byte(0xA0));
130 }
131
132 #[test]
133 fn ebcdic_high_bytes_not_corrupted() {
134 assert!(!is_likely_corrupted_ebcdic_byte(0xC1));
136 assert!(!is_likely_corrupted_ebcdic_byte(0xF0));
137 }
138
139 #[test]
142 fn comp3_invalid_high_nibble_detection() {
143 assert!(is_invalid_comp3_high_nibble(0xA2));
144 assert!(is_invalid_comp3_high_nibble(0xBE));
145 assert!(!is_invalid_comp3_high_nibble(0x12));
146 }
147
148 #[test]
149 fn comp3_high_nibble_valid_digits_0_to_9() {
150 for high in 0..=9u8 {
151 assert!(
152 !is_invalid_comp3_high_nibble(high << 4),
153 "high nibble {high} should be valid"
154 );
155 }
156 }
157
158 #[test]
159 fn comp3_high_nibble_a_b_e_invalid() {
160 assert!(is_invalid_comp3_high_nibble(0xA0));
161 assert!(is_invalid_comp3_high_nibble(0xB0));
162 assert!(is_invalid_comp3_high_nibble(0xE0));
163 }
164
165 #[test]
166 fn comp3_high_nibble_c_d_f_valid() {
167 assert!(!is_invalid_comp3_high_nibble(0xC0));
169 assert!(!is_invalid_comp3_high_nibble(0xD0));
170 assert!(!is_invalid_comp3_high_nibble(0xF0));
171 }
172
173 #[test]
176 fn comp3_invalid_low_nibble_detection() {
177 assert!(is_invalid_comp3_low_nibble(0x0A));
178 assert!(is_invalid_comp3_low_nibble(0x5B));
179 assert!(!is_invalid_comp3_low_nibble(0x56));
180 }
181
182 #[test]
183 fn comp3_low_nibble_valid_digits_0_to_9() {
184 for low in 0..=9u8 {
185 assert!(
186 !is_invalid_comp3_low_nibble(low),
187 "low nibble {low} should be valid"
188 );
189 }
190 }
191
192 #[test]
193 fn comp3_low_nibble_a_b_e_invalid() {
194 assert!(is_invalid_comp3_low_nibble(0x0A));
195 assert!(is_invalid_comp3_low_nibble(0x0B));
196 assert!(is_invalid_comp3_low_nibble(0x0E));
197 }
198
199 #[test]
200 fn comp3_low_nibble_c_d_f_valid() {
201 assert!(!is_invalid_comp3_low_nibble(0x0C));
203 assert!(!is_invalid_comp3_low_nibble(0x0D));
204 assert!(!is_invalid_comp3_low_nibble(0x0F));
205 }
206
207 #[test]
210 fn comp3_invalid_sign_nibble_detection() {
211 assert!(is_invalid_comp3_sign_nibble(0x12));
212 assert!(!is_invalid_comp3_sign_nibble(0x1C));
213 assert!(!is_invalid_comp3_sign_nibble(0x1D));
214 }
215
216 #[test]
217 fn comp3_sign_nibble_digits_0_to_9_all_invalid() {
218 for low in 0..=9u8 {
219 assert!(
220 is_invalid_comp3_sign_nibble(low),
221 "sign nibble {low} should be invalid"
222 );
223 }
224 }
225
226 #[test]
227 fn comp3_sign_nibble_c_d_f_all_valid() {
228 assert!(!is_invalid_comp3_sign_nibble(0x0C)); assert!(!is_invalid_comp3_sign_nibble(0x0D)); assert!(!is_invalid_comp3_sign_nibble(0x0F)); }
232
233 #[test]
234 fn comp3_sign_nibble_a_b_e_also_valid() {
235 assert!(!is_invalid_comp3_sign_nibble(0x0A));
237 assert!(!is_invalid_comp3_sign_nibble(0x0B));
238 assert!(!is_invalid_comp3_sign_nibble(0x0E));
239 }
240}