1#![cfg_attr(not(any(test, feature = "std")), no_std)]
12
13pub mod baseline;
14mod combine;
15pub mod specialized;
16mod tables;
17
18#[cfg(not(feature = "std"))]
19use core::hash::Hasher;
20#[cfg(feature = "std")]
21use std::hash::Hasher;
22
23const DEFAULT_CRC32: u32 = 0xffffffff;
24
25#[derive(Clone, Copy, Debug, Eq, PartialEq)]
26enum State {
27 Baseline(baseline::State),
28 Specialized(specialized::State),
29}
30
31#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub struct Crc32 {
34 len: u64,
35 state: State,
36}
37
38impl Crc32 {
39 pub fn new() -> Self {
41 Self::new_with_initial(DEFAULT_CRC32, 0)
42 }
43
44 pub fn new_with_initial(crc: u32, len: u64) -> Self {
50 let state = specialized::State::new(crc).map_or_else(
51 || State::Baseline(baseline::State::new(crc)),
52 State::Specialized,
53 );
54 Self { len, state }
55 }
56
57 pub fn as_u32(&self) -> u32 {
59 match self.state {
60 State::Baseline(ref state) => state.as_u32(),
61 State::Specialized(ref state) => state.as_u32(),
62 }
63 }
64
65 pub fn is_empty(&self) -> bool {
67 self.len == 0
68 }
69
70 pub fn len(&self) -> u64 {
72 self.len
73 }
74
75 pub fn reset(&mut self) {
77 self.len = 0;
78 match self.state {
79 State::Baseline(ref mut state) => state.reset(),
80 State::Specialized(ref mut state) => state.reset(),
81 }
82 }
83
84 pub fn update(&mut self, bytes: &[u8]) {
86 self.len += bytes.len() as u64;
87 match self.state {
88 State::Baseline(ref mut state) => state.update(bytes),
89 State::Specialized(ref mut state) => state.update(bytes),
90 }
91 }
92
93 pub fn combine(a: &Self, b: &Self) -> Self {
95 let (crc1, crc2) = (a.as_u32(), b.as_u32());
96 Self::new_with_initial(combine::combine(crc1, crc2, b.len), a.len + b.len)
97 }
98}
99
100impl Default for Crc32 {
101 fn default() -> Self {
102 Self::new()
103 }
104}
105
106impl Hasher for Crc32 {
107 fn finish(&self) -> u64 {
108 self.as_u32() as u64
109 }
110
111 fn write(&mut self, bytes: &[u8]) {
112 self.update(bytes);
113 }
114}
115
116impl PartialEq<u32> for Crc32 {
117 fn eq(&self, &other: &u32) -> bool {
118 self.as_u32() == other
119 }
120}
121
122impl PartialEq<Crc32> for u32 {
123 fn eq(&self, other: &Crc32) -> bool {
124 *self == other.as_u32()
125 }
126}
127
128#[cfg(test)]
129fn golden(crc: u32, bytes: &[u8]) -> u32 {
130 bytes.iter().fold(crc, |mut crc, &byte| {
131 crc ^= u32::from(byte) << 24;
132 for _ in 0..8 {
133 crc = if crc & 0x80000000 != 0 {
134 (crc << 1) ^ 0xaf
135 } else {
136 crc << 1
137 };
138 }
139 crc
140 })
141}
142
143#[cfg(test)]
144mod tests {
145 use quickcheck_macros::quickcheck;
146
147 use crate::golden;
148
149 const CHECK: u32 = 0xa5fd3138;
150
151 #[test]
152 fn golden_is_valid() {
153 assert_eq!(CHECK, golden(crate::DEFAULT_CRC32, b"123456789"));
154 }
155
156 #[quickcheck]
157 fn check(data: Vec<u8>) -> bool {
158 let mut crc32 = super::Crc32::new();
159 crc32.update(data.as_slice());
160 crc32.as_u32() == golden(crate::DEFAULT_CRC32, data.as_slice())
161 }
162
163 #[test]
164 fn check_combine() {
165 let mut crc_a = super::Crc32::new();
166 let mut crc_b = super::Crc32::new();
167 crc_a.update(b"12345");
168 crc_b.update(b"6789");
169 assert_eq!(CHECK, super::Crc32::combine(&crc_a, &crc_b));
170 }
171}