1use core::mem::MaybeUninit;
8
9#[inline(always)]
22pub fn slice_by_8(buf: &[u8], lookup_table: &[[u32; 256]; 8]) -> u32 {
23 slice_by_8_with_seed(buf, 0, lookup_table)
24}
25
26pub fn slice_by_8_with_seed(buf: &[u8], seed: u32, lookup_table: &[[u32; 256]; 8]) -> u32 {
39 let mut crc = !seed;
40
41 let (prefix, shorts, suffix) = unsafe { buf.align_to::<u64>() };
43 crc = prefix.iter().fold(crc, |acc, byte| {
44 lookup_table[0][((acc ^ *byte as u32) & 0xff) as usize] ^ (acc >> 8)
45 });
46
47 #[cfg(target_endian = "big")]
49 let process_8_bytes_at_once = |acc: u32, byte: &u64| {
50 let byte = *byte;
51 let (low, high) = (
52 (byte as u32) ^ acc.reverse_bits(),
53 (byte >> u32::BITS) as u32,
54 );
55 lookup_table[0][(high & 0xFF) as usize]
56 ^ lookup_table[1][((high >> 8) & 0xFF) as usize]
57 ^ lookup_table[2][((high >> 16) & 0xFF) as usize]
58 ^ lookup_table[3][((high >> 24) & 0xFF) as usize]
59 ^ lookup_table[4][(low & 0xFF) as usize]
60 ^ lookup_table[5][((low >> 8) & 0xFF) as usize]
61 ^ lookup_table[6][((low >> 16) & 0xFF) as usize]
62 ^ lookup_table[7][((low >> 24) & 0xFF) as usize]
63 };
64
65 #[cfg(target_endian = "little")]
66 let process_8_bytes_at_once = |acc: u32, byte: &u64| {
67 let byte = *byte;
68 let (low, high) = ((byte as u32) ^ acc, (byte >> u32::BITS) as u32);
69 lookup_table[0][((high >> 24) & 0xFF) as usize]
70 ^ lookup_table[1][((high >> 16) & 0xFF) as usize]
71 ^ lookup_table[2][((high >> 8) & 0xFF) as usize]
72 ^ lookup_table[3][(high & 0xFF) as usize]
73 ^ lookup_table[4][((low >> 24) & 0xFF) as usize]
74 ^ lookup_table[5][((low >> 16) & 0xFF) as usize]
75 ^ lookup_table[6][((low >> 8) & 0xFF) as usize]
76 ^ lookup_table[7][(low & 0xFF) as usize]
77 };
78 crc = shorts.iter().fold(crc, process_8_bytes_at_once);
79
80 !suffix.iter().fold(crc, |acc, byte| {
82 (acc >> 8) ^ lookup_table[0][((acc ^ *byte as u32) & 0xff) as usize]
83 })
84}
85
86pub fn generate_table(polynomial: u32) -> [[u32; 256]; 8] {
96 let mut generated_lookup_table = MaybeUninit::<[[u32; 256]; 8]>::uninit();
97
98 unsafe {
101 for (i, x) in generated_lookup_table.assume_init_mut()[0]
103 .iter_mut()
104 .enumerate()
105 {
106 *x = (0..8).fold(i as u32, |acc, _| {
107 (acc >> 1) ^ ((acc & 1) * polynomial.reverse_bits())
108 });
109 }
110
111 let table_0 = &generated_lookup_table.assume_init()[0];
113 for i in 1..=7 {
114 let table_before = &generated_lookup_table.assume_init()[i - 1];
115 for (i, x) in generated_lookup_table.assume_init_mut()[i]
116 .iter_mut()
117 .enumerate()
118 {
119 *x = (table_before[i] >> 8) ^ table_0[(table_before[i] & 0xFF) as usize];
120 }
121 }
122 *generated_lookup_table.assume_init_mut()
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use crate as slice_by_8;
129 use slice_by_8::crc32::LOOKUP_TABLE;
130
131 #[test]
132 fn slice_by_8_no_seed() {
133 const HASH_ME: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
134 assert_eq!(slice_by_8::slice_by_8(HASH_ME, &LOOKUP_TABLE), 0x4C2750BD);
135 }
136
137 #[test]
138 fn slice_by_8_with_seed() {
139 const HASH_ME: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
140 assert_eq!(
141 slice_by_8::slice_by_8_with_seed(HASH_ME, 123456789, &LOOKUP_TABLE),
142 0xEADB5034
143 );
144 }
145}