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]
169pub(crate) const fn control_kind(b: u8) -> ErrorKind {
170 match b {
171 b'\r' => ErrorKind::BareCr,
172 b'\n' => ErrorKind::LineFeed,
173 0 => ErrorKind::Nul,
174 _ => ErrorKind::Control,
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use std::vec;
181
182 use super::*;
183
184 #[test]
185 fn test_find_byte_matches_position() {
186 let hay: std::vec::Vec<u8> = (0..64u8).collect();
187 for needle in 0..70u8 {
188 assert_eq!(
189 find_byte(needle, &hay),
190 hay.iter().position(|&b| b == needle)
191 );
192 }
193 assert_eq!(find_byte(b'\n', b"\x0b\x0a"), Some(1));
194 assert_eq!(find_byte(1, &[0x81, 0x01]), Some(1));
195 assert_eq!(find_byte(b'a', b""), None);
196 }
197
198 #[test]
199 fn test_find_byte_false_marker_above_true_one() {
200 let hay = [2u8, 2, 1, 0, 1, 2, 2, 2, 2];
202 assert_eq!(find_byte(1, &hay), Some(2));
203 assert_eq!(find_byte(0, &hay), Some(3));
204 }
205
206 #[test]
207 fn test_find_either_every_position() {
208 for len in 0..20usize {
209 for pos_a in 0..len {
210 let mut v = vec![b'x'; len];
211 v[pos_a] = b',';
212 for pos_b in 0..len {
213 let mut w = v.clone();
214 w[pos_b] = b'"';
215 let expected = w.iter().position(|&b| b == b',' || b == b'"');
216 assert_eq!(find_either(b',', b'"', &w), expected);
217 }
218 }
219 }
220 }
221
222 #[test]
223 fn test_field_value_rejects_controls_with_kinds() {
224 assert!(check_field_value(b"").is_ok());
225 assert!(check_field_value(b"text/html; q=0.9\tx").is_ok());
226 assert!(check_field_value(b"caf\xc3\xa9 \x80\xff").is_ok());
227 let e = check_field_value(b"a\rb").unwrap_err();
228 assert_eq!((e.kind(), e.offset()), (ErrorKind::BareCr, 1));
229 let e = check_field_value(b"abcdefgh\x00ijk").unwrap_err();
230 assert_eq!((e.kind(), e.offset()), (ErrorKind::Nul, 8));
231 let e = check_field_value(b"abcdefghijklmno\x7f").unwrap_err();
232 assert_eq!((e.kind(), e.offset()), (ErrorKind::Control, 15));
233 let e = check_field_value(b"abcdefg\nhij").unwrap_err();
234 assert_eq!((e.kind(), e.offset()), (ErrorKind::LineFeed, 7));
235 assert_eq!(
236 check_field_value(b"\x0b").unwrap_err().kind(),
237 ErrorKind::Control
238 );
239 assert_eq!(
240 check_field_value(b"\x0c").unwrap_err().kind(),
241 ErrorKind::Control
242 );
243 }
244
245 #[test]
246 fn test_field_value_fast_path_agrees_with_bytewise() {
247 for b in 0u8..=255 {
248 for pos in 0..17 {
249 let mut v = vec![b'a'; 17];
250 v[pos] = b;
251 let fast = check_field_value(&v);
252 let slow = check_field_bytes(&v, 0);
253 assert_eq!(fast, slow, "byte {b:#04x} at {pos}");
254 }
255 }
256 }
257
258 #[test]
259 fn test_field_value_one_mebibyte() {
260 let v = vec![b'a'; 1 << 20];
261 assert!(check_field_value(&v).is_ok());
262 }
263
264 #[test]
265 fn test_first_not_in_positions() {
266 assert_eq!(first_not_in(b"", Class::TCHAR), None);
267 assert_eq!(first_not_in(b" a", Class::TCHAR), Some(0));
268 }
269}