1use crate::{
9 class::{self, Class},
10 error::{ErrorKind, Result, err},
11};
12
13const LO: u64 = 0x0101_0101_0101_0101;
14const HI: u64 = 0x8080_8080_8080_8080;
15
16#[inline]
19const fn zero_markers(x: u64) -> u64 {
20 x.wrapping_sub(LO) & !x & HI
21}
22
23#[inline]
24fn word(chunk: &[u8]) -> u64 {
25 let mut bytes = [0u8; 8];
26 if let Ok(exact) = <[u8; 8]>::try_from(chunk) {
27 bytes = exact;
28 }
29 u64::from_le_bytes(bytes)
30}
31
32#[inline]
33fn first_marker(markers: u64) -> usize {
34 (markers.trailing_zeros() / 8) as usize
35}
36
37#[inline]
51#[must_use]
52pub fn find_byte(needle: u8, hay: &[u8]) -> Option<usize> {
53 let pattern = u64::from_le_bytes([needle; 8]);
54 let mut chunks = hay.chunks_exact(8);
55 let mut base = 0usize;
56 for chunk in &mut chunks {
57 let found = zero_markers(word(chunk) ^ pattern);
58 if found != 0 {
59 return Some(base + first_marker(found));
60 }
61 base += 8;
62 }
63 chunks
64 .remainder()
65 .iter()
66 .position(|&b| b == needle)
67 .map(|i| base + i)
68}
69
70#[inline]
80#[must_use]
81pub fn find_either(a: u8, b: u8, hay: &[u8]) -> Option<usize> {
82 let pa = u64::from_le_bytes([a; 8]);
83 let pb = u64::from_le_bytes([b; 8]);
84 let mut chunks = hay.chunks_exact(8);
85 let mut base = 0usize;
86 for chunk in &mut chunks {
87 let w = word(chunk);
88 let found = zero_markers(w ^ pa) | zero_markers(w ^ pb);
89 if found != 0 {
90 return Some(base + first_marker(found));
93 }
94 base += 8;
95 }
96 chunks
97 .remainder()
98 .iter()
99 .position(|&x| x == a || x == b)
100 .map(|i| base + i)
101}
102
103#[inline]
114#[must_use]
115pub fn first_not_in(s: &[u8], class: Class) -> Option<usize> {
116 s.iter().position(|&b| !class.contains(b))
117}
118
119#[inline]
141pub fn check_field_value(value: &[u8]) -> Result<()> {
142 let mut chunks = value.chunks_exact(8);
143 let mut base = 0usize;
144 for chunk in &mut chunks {
145 let w = word(chunk);
146 let low = w.wrapping_sub(0x2020_2020_2020_2020) & !w & HI;
150 let del = zero_markers(w ^ 0x7f7f_7f7f_7f7f_7f7f);
151 if (low | del | (w & HI)) != 0 {
152 check_field_bytes(chunk, base)?;
153 }
154 base += 8;
155 }
156 check_field_bytes(chunks.remainder(), base)
157}
158
159#[inline]
160fn check_field_bytes(bytes: &[u8], base: usize) -> Result<()> {
161 match bytes.iter().position(|&b| !class::is_field_text(b)) {
162 None => Ok(()),
163 Some(i) => err(control_kind(bytes.get(i).copied().unwrap_or(0)), base + i),
164 }
165}
166
167#[inline]
171pub(crate) const fn is_control(b: u8) -> bool {
172 (b < 0x20 && b != 0x09) || b == 0x7f
173}
174
175#[inline]
177pub(crate) const fn control_kind(b: u8) -> ErrorKind {
178 match b {
179 b'\r' => ErrorKind::BareCr,
180 b'\n' => ErrorKind::LineFeed,
181 0 => ErrorKind::Nul,
182 _ => ErrorKind::Control,
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use std::vec;
189
190 use super::*;
191
192 #[test]
193 fn test_find_byte_matches_position() {
194 let hay: std::vec::Vec<u8> = (0..64u8).collect();
195 for needle in 0..70u8 {
196 assert_eq!(
197 find_byte(needle, &hay),
198 hay.iter().position(|&b| b == needle)
199 );
200 }
201 assert_eq!(find_byte(b'\n', b"\x0b\x0a"), Some(1));
202 assert_eq!(find_byte(1, &[0x81, 0x01]), Some(1));
203 assert_eq!(find_byte(b'a', b""), None);
204 }
205
206 #[test]
207 fn test_find_byte_false_marker_above_true_one() {
208 let hay = [2u8, 2, 1, 0, 1, 2, 2, 2, 2];
210 assert_eq!(find_byte(1, &hay), Some(2));
211 assert_eq!(find_byte(0, &hay), Some(3));
212 }
213
214 #[test]
215 fn test_find_either_every_position() {
216 for len in 0..20usize {
217 for pos_a in 0..len {
218 let mut v = vec![b'x'; len];
219 v[pos_a] = b',';
220 for pos_b in 0..len {
221 let mut w = v.clone();
222 w[pos_b] = b'"';
223 let expected = w.iter().position(|&b| b == b',' || b == b'"');
224 assert_eq!(find_either(b',', b'"', &w), expected);
225 }
226 }
227 }
228 }
229
230 #[test]
231 fn test_field_value_rejects_controls_with_kinds() {
232 assert!(check_field_value(b"").is_ok());
233 assert!(check_field_value(b"text/html; q=0.9\tx").is_ok());
234 assert!(check_field_value(b"caf\xc3\xa9 \x80\xff").is_ok());
235 let e = check_field_value(b"a\rb").unwrap_err();
236 assert_eq!((e.kind(), e.offset()), (ErrorKind::BareCr, 1));
237 let e = check_field_value(b"abcdefgh\x00ijk").unwrap_err();
238 assert_eq!((e.kind(), e.offset()), (ErrorKind::Nul, 8));
239 let e = check_field_value(b"abcdefghijklmno\x7f").unwrap_err();
240 assert_eq!((e.kind(), e.offset()), (ErrorKind::Control, 15));
241 let e = check_field_value(b"abcdefg\nhij").unwrap_err();
242 assert_eq!((e.kind(), e.offset()), (ErrorKind::LineFeed, 7));
243 assert_eq!(
244 check_field_value(b"\x0b").unwrap_err().kind(),
245 ErrorKind::Control
246 );
247 assert_eq!(
248 check_field_value(b"\x0c").unwrap_err().kind(),
249 ErrorKind::Control
250 );
251 }
252
253 #[test]
254 fn test_field_value_fast_path_agrees_with_bytewise() {
255 for b in 0u8..=255 {
256 for pos in 0..17 {
257 let mut v = vec![b'a'; 17];
258 v[pos] = b;
259 let fast = check_field_value(&v);
260 let slow = check_field_bytes(&v, 0);
261 assert_eq!(fast, slow, "byte {b:#04x} at {pos}");
262 }
263 }
264 }
265
266 #[test]
267 fn test_field_value_one_mebibyte() {
268 let v = vec![b'a'; 1 << 20];
269 assert!(check_field_value(&v).is_ok());
270 }
271
272 #[test]
273 fn test_first_not_in_positions() {
274 assert_eq!(first_not_in(b"", Class::TCHAR), None);
275 assert_eq!(first_not_in(b" a", Class::TCHAR), Some(0));
276 }
277}