• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! ## Example
2 //!
3 //! ```rust
4 //! use crc32fast::Hasher;
5 //!
6 //! let mut hasher = Hasher::new();
7 //! hasher.update(b"foo bar baz");
8 //! let checksum = hasher.finalize();
9 //! ```
10 //!
11 //! ## Performance
12 //!
13 //! This crate contains multiple CRC32 implementations:
14 //!
15 //! - A fast baseline implementation which processes up to 16 bytes per iteration
16 //! - An optimized implementation for modern `x86` using `sse` and `pclmulqdq` instructions
17 //!
18 //! Calling the `Hasher::new` constructor at runtime will perform a feature detection to select the most
19 //! optimal implementation for the current CPU feature set.
20 
21 #![cfg_attr(not(feature = "std"), no_std)]
22 #![cfg_attr(
23     all(feature = "nightly", target_arch = "aarch64"),
24     feature(stdsimd, aarch64_target_feature)
25 )]
26 
27 #[deny(missing_docs)]
28 #[cfg(test)]
29 #[macro_use]
30 extern crate quickcheck;
31 
32 #[macro_use]
33 extern crate cfg_if;
34 
35 #[cfg(feature = "std")]
36 use std as core;
37 
38 use core::fmt;
39 use core::hash;
40 
41 mod baseline;
42 mod combine;
43 mod specialized;
44 mod table;
45 
46 #[derive(Clone)]
47 enum State {
48     Baseline(baseline::State),
49     Specialized(specialized::State),
50 }
51 
52 #[derive(Clone)]
53 /// Represents an in-progress CRC32 computation.
54 pub struct Hasher {
55     amount: u64,
56     state: State,
57 }
58 
59 const DEFAULT_INIT_STATE: u32 = 0;
60 
61 impl Hasher {
62     /// Create a new `Hasher`.
63     ///
64     /// This will perform a CPU feature detection at runtime to select the most
65     /// optimal implementation for the current processor architecture.
new() -> Self66     pub fn new() -> Self {
67         Self::new_with_initial(DEFAULT_INIT_STATE)
68     }
69 
70     /// Create a new `Hasher` with an initial CRC32 state.
71     ///
72     /// This works just like `Hasher::new`, except that it allows for an initial
73     /// CRC32 state to be passed in.
new_with_initial(init: u32) -> Self74     pub fn new_with_initial(init: u32) -> Self {
75         Self::internal_new_specialized(init).unwrap_or_else(|| Self::internal_new_baseline(init))
76     }
77 
78     #[doc(hidden)]
79     // Internal-only API. Don't use.
internal_new_baseline(init: u32) -> Self80     pub fn internal_new_baseline(init: u32) -> Self {
81         Hasher {
82             amount: 0,
83             state: State::Baseline(baseline::State::new(init)),
84         }
85     }
86 
87     #[doc(hidden)]
88     // Internal-only API. Don't use.
internal_new_specialized(init: u32) -> Option<Self>89     pub fn internal_new_specialized(init: u32) -> Option<Self> {
90         {
91             if let Some(state) = specialized::State::new(init) {
92                 return Some(Hasher {
93                     amount: 0,
94                     state: State::Specialized(state),
95                 });
96             }
97         }
98         None
99     }
100 
101     /// Process the given byte slice and update the hash state.
update(&mut self, buf: &[u8])102     pub fn update(&mut self, buf: &[u8]) {
103         self.amount += buf.len() as u64;
104         match self.state {
105             State::Baseline(ref mut state) => state.update(buf),
106             State::Specialized(ref mut state) => state.update(buf),
107         }
108     }
109 
110     /// Finalize the hash state and return the computed CRC32 value.
finalize(self) -> u32111     pub fn finalize(self) -> u32 {
112         match self.state {
113             State::Baseline(state) => state.finalize(),
114             State::Specialized(state) => state.finalize(),
115         }
116     }
117 
118     /// Reset the hash state.
reset(&mut self)119     pub fn reset(&mut self) {
120         self.amount = 0;
121         match self.state {
122             State::Baseline(ref mut state) => state.reset(),
123             State::Specialized(ref mut state) => state.reset(),
124         }
125     }
126 
127     /// Combine the hash state with the hash state for the subsequent block of bytes.
combine(&mut self, other: &Self)128     pub fn combine(&mut self, other: &Self) {
129         self.amount += other.amount;
130         let other_crc = other.clone().finalize();
131         match self.state {
132             State::Baseline(ref mut state) => state.combine(other_crc, other.amount),
133             State::Specialized(ref mut state) => state.combine(other_crc, other.amount),
134         }
135     }
136 }
137 
138 impl fmt::Debug for Hasher {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result139     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140         f.debug_struct("crc32fast::Hasher").finish()
141     }
142 }
143 
144 impl Default for Hasher {
default() -> Self145     fn default() -> Self {
146         Self::new()
147     }
148 }
149 
150 impl hash::Hasher for Hasher {
write(&mut self, bytes: &[u8])151     fn write(&mut self, bytes: &[u8]) {
152         self.update(bytes)
153     }
154 
finish(&self) -> u64155     fn finish(&self) -> u64 {
156         u64::from(self.clone().finalize())
157     }
158 }
159 
160 #[cfg(test)]
161 mod test {
162     use super::Hasher;
163 
164     quickcheck! {
165         fn combine(bytes_1: Vec<u8>, bytes_2: Vec<u8>) -> bool {
166             let mut hash_a = Hasher::new();
167             hash_a.update(&bytes_1);
168             hash_a.update(&bytes_2);
169             let mut hash_b = Hasher::new();
170             hash_b.update(&bytes_2);
171             let mut hash_c = Hasher::new();
172             hash_c.update(&bytes_1);
173             hash_c.combine(&hash_b);
174 
175             hash_a.finalize() == hash_c.finalize()
176         }
177     }
178 }
179