crc32fast/
lib.rs

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]
30extern crate quickcheck;
31
32#[macro_use]
33extern crate cfg_if;
34
35#[cfg(feature = "std")]
36use std as core;
37
38use core::fmt;
39use core::hash;
40
41mod baseline;
42mod combine;
43mod specialized;
44mod table;
45
46#[derive(Clone)]
47enum State {
48    Baseline(baseline::State),
49    Specialized(specialized::State),
50}
51
52#[derive(Clone)]
53/// Represents an in-progress CRC32 computation.
54pub struct Hasher {
55    amount: u64,
56    state: State,
57}
58
59const DEFAULT_INIT_STATE: u32 = 0;
60
61impl 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.
66    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.
74    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.
80    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.
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.
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.
111    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.
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.
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
138impl fmt::Debug for Hasher {
139    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140        f.debug_struct("crc32fast::Hasher").finish()
141    }
142}
143
144impl Default for Hasher {
145    fn default() -> Self {
146        Self::new()
147    }
148}
149
150impl hash::Hasher for Hasher {
151    fn write(&mut self, bytes: &[u8]) {
152        self.update(bytes)
153    }
154
155    fn finish(&self) -> u64 {
156        u64::from(self.clone().finalize())
157    }
158}
159
160#[cfg(test)]
161mod 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}