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