1pub struct Word;
2
3impl Word {
4 pub fn swar_eq_ci<const N: usize>(haystack: &[u8], expected: &[u8; N]) -> bool {
5 let Some(h) = haystack.first_chunk::<N>() else {
6 return false;
7 };
8 const M64: u64 = u64::from_le_bytes([0x20; 8]);
9 const M32: u32 = u32::from_le_bytes([0x20; 4]);
10 const M16: u16 = u16::from_le_bytes([0x20; 2]);
11 let mut i = 0usize;
12 while i + 8 <= N {
13 let raw = u64::from_le_bytes(h[i..i + 8].try_into().unwrap()) | M64;
14 let exp = u64::from_le_bytes(expected[i..i + 8].try_into().unwrap());
15 if raw != exp {
16 return false;
17 }
18 i += 8;
19 }
20 if i + 4 <= N {
21 let raw = u32::from_le_bytes(h[i..i + 4].try_into().unwrap()) | M32;
22 let exp = u32::from_le_bytes(expected[i..i + 4].try_into().unwrap());
23 if raw != exp {
24 return false;
25 }
26 i += 4;
27 }
28 if i + 2 <= N {
29 let raw = u16::from_le_bytes(h[i..i + 2].try_into().unwrap()) | M16;
30 let exp = u16::from_le_bytes(expected[i..i + 2].try_into().unwrap());
31 if raw != exp {
32 return false;
33 }
34 i += 2;
35 }
36 if i < N && h[i] | 0x20 != expected[i] {
37 return false;
38 }
39 true
40 }
41}
42
43pub struct Ascii;
44
45impl Ascii {
46 #[inline(always)]
47 pub fn fold_usize(mut acc: usize, chunk: &[u8]) -> Option<usize> {
48 for &b in chunk {
49 if !b.is_ascii_digit() {
50 return None;
51 }
52 acc = acc.checked_mul(10)?.checked_add((b - b'0') as usize)?;
53 }
54 Some(acc)
55 }
56
57 #[inline(always)]
58 pub fn fold_u64(mut acc: u64, chunk: &[u8]) -> Option<u64> {
59 for &b in chunk {
60 if !b.is_ascii_digit() {
61 return None;
62 }
63 acc = acc.checked_mul(10)?.checked_add((b - b'0') as u64)?;
64 }
65 Some(acc)
66 }
67
68 #[inline(always)]
69 pub fn parse_usize(bytes: &[u8]) -> Option<usize> {
70 if bytes.is_empty() {
71 return None;
72 }
73 Self::fold_usize(0, bytes)
74 }
75
76 #[inline(always)]
77 pub fn parse_u64(bytes: &[u8]) -> Option<u64> {
78 if bytes.is_empty() {
79 return None;
80 }
81 Self::fold_u64(0, bytes)
82 }
83}