byond_crc32/
baseline.rs

1use crate::{
2    tables::{BYTE_TABLE, WORD_TABLE},
3    DEFAULT_CRC32,
4};
5
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub struct State {
8    state: u32,
9}
10
11impl State {
12    pub fn new(state: u32) -> Self {
13        State { state }
14    }
15
16    pub fn update(&mut self, buf: &[u8]) {
17        self.state = slice_by_16(self.state, buf);
18    }
19
20    pub fn as_u32(self) -> u32 {
21        self.state
22    }
23
24    pub fn reset(&mut self) {
25        self.state = DEFAULT_CRC32;
26    }
27}
28
29#[inline(always)]
30pub(crate) fn slice_by_16(mut crc: u32, bytes: &[u8]) -> u32 {
31    crc = u32::swap_bytes(crc);
32    let chunks = bytes.chunks_exact(16);
33    let remainder = chunks.remainder();
34    crc = chunks.fold(crc, |mut crc, word| {
35        crc ^= u32::from_le_bytes(word[0..4].try_into().unwrap());
36        WORD_TABLE[15][(crc & 0xff) as usize]
37            ^ WORD_TABLE[14][((crc >> 8) & 0xff) as usize]
38            ^ WORD_TABLE[13][((crc >> 16) & 0xff) as usize]
39            ^ WORD_TABLE[12][(crc >> 24) as usize]
40            ^ WORD_TABLE[11][word[4] as usize]
41            ^ WORD_TABLE[10][word[5] as usize]
42            ^ WORD_TABLE[9][word[6] as usize]
43            ^ WORD_TABLE[8][word[7] as usize]
44            ^ WORD_TABLE[7][word[8] as usize]
45            ^ WORD_TABLE[6][word[9] as usize]
46            ^ WORD_TABLE[5][word[10] as usize]
47            ^ WORD_TABLE[4][word[11] as usize]
48            ^ WORD_TABLE[3][word[12] as usize]
49            ^ WORD_TABLE[2][word[13] as usize]
50            ^ WORD_TABLE[1][word[14] as usize]
51            ^ WORD_TABLE[0][word[15] as usize]
52    });
53    crc = u32::swap_bytes(crc);
54    slice_by_1(crc, remainder)
55}
56
57#[inline(always)]
58pub(crate) fn slice_by_1(crc: u32, bytes: &[u8]) -> u32 {
59    bytes.iter().fold(crc, |crc, &byte| {
60        (crc << 8) ^ BYTE_TABLE[(crc >> 24) as usize ^ byte as usize]
61    })
62}
63
64#[cfg(test)]
65mod tests {
66    use crate::golden;
67    use quickcheck_macros::quickcheck;
68
69    #[quickcheck]
70    fn slice_by_16_matches_golden(crc: u32, bytes: Vec<u8>) -> bool {
71        super::slice_by_16(crc, &bytes) == golden(crc, &bytes)
72    }
73
74    #[quickcheck]
75    fn slice_by_1_matches_golden(crc: u32, bytes: Vec<u8>) -> bool {
76        super::slice_by_1(crc, &bytes) == golden(crc, &bytes)
77    }
78}