1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
use crate::traits::{CRC32, POLYNOMIAL_CRC32C, POLYNOMIAL_CRC32_IEEE};

#[inline]
pub fn compute<S: CRC32<P>, const P: u32>(s: S, init: u32, data: &[u8]) -> u32 {
    let mut crc = !init;

    let (prefix, middle, suffix) = unsafe { data.align_to::<u64>() };

    let fold_u8 = |crc, value| s.crc32_u8(crc, value);
    crc = fold_copied(prefix, crc, fold_u8);

    crc = {
        let fold_u64 = |crc, value| s.crc32_u64(crc, value);
        let fold_chunk = |crc, chunk: &[u64]| fold_copied(chunk, crc, fold_u64);
        let mut iter = middle.chunks_exact(8);
        let crc = iter.by_ref().fold(crc, fold_chunk);
        fold_copied(iter.remainder(), crc, fold_u64)
    };

    crc = fold_copied(suffix, crc, fold_u8);

    !crc
}

fn fold_copied<T: Copy, B>(slice: &[T], init: B, f: impl Fn(B, T) -> B) -> B {
    slice.iter().copied().fold(init, f)
}

#[inline]
pub fn compute_crc32_ieee<S: CRC32<POLYNOMIAL_CRC32_IEEE>>(s: S, init: u32, data: &[u8]) -> u32 {
    compute::<S, POLYNOMIAL_CRC32_IEEE>(s, init, data)
}

#[inline]
pub fn compute_crc32c<S: CRC32<POLYNOMIAL_CRC32C>>(s: S, init: u32, data: &[u8]) -> u32 {
    compute::<S, POLYNOMIAL_CRC32C>(s, init, data)
}