/rust/registry/src/index.crates.io-1949cf8c6b5b557f/crc32fast-1.5.0/src/lib.rs
Line  | Count  | Source  | 
1  |  | //! Fast, SIMD-accelerated CRC32 (IEEE) checksum computation.  | 
2  |  | //!  | 
3  |  | //! ## Usage  | 
4  |  | //!  | 
5  |  | //! ### Simple usage  | 
6  |  | //!  | 
7  |  | //! For simple use-cases, you can call the [`hash()`] convenience function to  | 
8  |  | //! directly compute the CRC32 checksum for a given byte slice:  | 
9  |  | //!  | 
10  |  | //! ```rust  | 
11  |  | //! let checksum = crc32fast::hash(b"foo bar baz");  | 
12  |  | //! ```  | 
13  |  | //!  | 
14  |  | //! ### Advanced usage  | 
15  |  | //!  | 
16  |  | //! For use-cases that require more flexibility or performance, for example when  | 
17  |  | //! processing large amounts of data, you can create and manipulate a [`Hasher`]:  | 
18  |  | //!  | 
19  |  | //! ```rust  | 
20  |  | //! use crc32fast::Hasher;  | 
21  |  | //!  | 
22  |  | //! let mut hasher = Hasher::new();  | 
23  |  | //! hasher.update(b"foo bar baz");  | 
24  |  | //! let checksum = hasher.finalize();  | 
25  |  | //! ```  | 
26  |  | //!  | 
27  |  | //! ## Performance  | 
28  |  | //!  | 
29  |  | //! This crate contains multiple CRC32 implementations:  | 
30  |  | //!  | 
31  |  | //! - A fast baseline implementation which processes up to 16 bytes per iteration  | 
32  |  | //! - An optimized implementation for modern `x86` using `sse` and `pclmulqdq` instructions  | 
33  |  | //!  | 
34  |  | //! Calling the [`Hasher::new`] constructor at runtime will perform a feature detection to select the most  | 
35  |  | //! optimal implementation for the current CPU feature set.  | 
36  |  |  | 
37  |  | #![cfg_attr(not(feature = "std"), no_std)]  | 
38  |  | #![deny(missing_docs)]  | 
39  |  | use core::fmt;  | 
40  |  | use core::hash;  | 
41  |  |  | 
42  |  | mod baseline;  | 
43  |  | mod combine;  | 
44  |  | mod specialized;  | 
45  |  | mod table;  | 
46  |  |  | 
47  |  | /// Computes the CRC32 hash of a byte slice.  | 
48  |  | ///  | 
49  |  | /// Check out [`Hasher`] for more advanced use-cases.  | 
50  | 0  | pub fn hash(buf: &[u8]) -> u32 { | 
51  | 0  |     let mut h = Hasher::new();  | 
52  | 0  |     h.update(buf);  | 
53  | 0  |     h.finalize()  | 
54  | 0  | }  | 
55  |  |  | 
56  |  | #[derive(Clone)]  | 
57  |  | enum State { | 
58  |  |     Baseline(baseline::State),  | 
59  |  |     Specialized(specialized::State),  | 
60  |  | }  | 
61  |  |  | 
62  |  | #[derive(Clone)]  | 
63  |  | /// Represents an in-progress CRC32 computation.  | 
64  |  | pub struct Hasher { | 
65  |  |     amount: u64,  | 
66  |  |     state: State,  | 
67  |  | }  | 
68  |  |  | 
69  |  | const DEFAULT_INIT_STATE: u32 = 0;  | 
70  |  |  | 
71  |  | impl Hasher { | 
72  |  |     /// Create a new `Hasher`.  | 
73  |  |     ///  | 
74  |  |     /// This will perform a CPU feature detection at runtime to select the most  | 
75  |  |     /// optimal implementation for the current processor architecture.  | 
76  | 185k  |     pub fn new() -> Self { | 
77  | 185k  |         Self::new_with_initial(DEFAULT_INIT_STATE)  | 
78  | 185k  |     }  | 
79  |  |  | 
80  |  |     /// Create a new `Hasher` with an initial CRC32 state.  | 
81  |  |     ///  | 
82  |  |     /// This works just like `Hasher::new`, except that it allows for an initial  | 
83  |  |     /// CRC32 state to be passed in.  | 
84  | 185k  |     pub fn new_with_initial(init: u32) -> Self { | 
85  | 185k  |         Self::new_with_initial_len(init, 0)  | 
86  | 185k  |     }  | 
87  |  |  | 
88  |  |     /// Create a new `Hasher` with an initial CRC32 state.  | 
89  |  |     ///  | 
90  |  |     /// As `new_with_initial`, but also accepts a length (in bytes). The  | 
91  |  |     /// resulting object can then be used with `combine` to compute `crc(a ||  | 
92  |  |     /// b)` from `crc(a)`, `crc(b)`, and `len(b)`.  | 
93  | 185k  |     pub fn new_with_initial_len(init: u32, amount: u64) -> Self { | 
94  | 185k  |         Self::internal_new_specialized(init, amount)  | 
95  | 185k  |             .unwrap_or_else(|| Self::internal_new_baseline(init, amount))  | 
96  | 185k  |     }  | 
97  |  |  | 
98  |  |     #[doc(hidden)]  | 
99  |  |     // Internal-only API. Don't use.  | 
100  | 0  |     pub fn internal_new_baseline(init: u32, amount: u64) -> Self { | 
101  | 0  |         Hasher { | 
102  | 0  |             amount,  | 
103  | 0  |             state: State::Baseline(baseline::State::new(init)),  | 
104  | 0  |         }  | 
105  | 0  |     }  | 
106  |  |  | 
107  |  |     #[doc(hidden)]  | 
108  |  |     // Internal-only API. Don't use.  | 
109  | 185k  |     pub fn internal_new_specialized(init: u32, amount: u64) -> Option<Self> { | 
110  |  |         { | 
111  | 185k  |             if let Some(state) = specialized::State::new(init) { | 
112  | 185k  |                 return Some(Hasher { | 
113  | 185k  |                     amount,  | 
114  | 185k  |                     state: State::Specialized(state),  | 
115  | 185k  |                 });  | 
116  | 0  |             }  | 
117  |  |         }  | 
118  | 0  |         None  | 
119  | 185k  |     }  | 
120  |  |  | 
121  |  |     /// Process the given byte slice and update the hash state.  | 
122  | 198k  |     pub fn update(&mut self, buf: &[u8]) { | 
123  | 198k  |         self.amount += buf.len() as u64;  | 
124  | 198k  |         match self.state { | 
125  | 0  |             State::Baseline(ref mut state) => state.update(buf),  | 
126  | 198k  |             State::Specialized(ref mut state) => state.update(buf),  | 
127  |  |         }  | 
128  | 198k  |     }  | 
129  |  |  | 
130  |  |     /// Finalize the hash state and return the computed CRC32 value.  | 
131  | 273k  |     pub fn finalize(self) -> u32 { | 
132  | 273k  |         match self.state { | 
133  | 0  |             State::Baseline(state) => state.finalize(),  | 
134  | 273k  |             State::Specialized(state) => state.finalize(),  | 
135  |  |         }  | 
136  | 273k  |     }  | 
137  |  |  | 
138  |  |     /// Reset the hash state.  | 
139  | 0  |     pub fn reset(&mut self) { | 
140  | 0  |         self.amount = 0;  | 
141  | 0  |         match self.state { | 
142  | 0  |             State::Baseline(ref mut state) => state.reset(),  | 
143  | 0  |             State::Specialized(ref mut state) => state.reset(),  | 
144  |  |         }  | 
145  | 0  |     }  | 
146  |  |  | 
147  |  |     /// Combine the hash state with the hash state for the subsequent block of bytes.  | 
148  | 0  |     pub fn combine(&mut self, other: &Self) { | 
149  | 0  |         self.amount += other.amount;  | 
150  | 0  |         let other_crc = other.clone().finalize();  | 
151  | 0  |         match self.state { | 
152  | 0  |             State::Baseline(ref mut state) => state.combine(other_crc, other.amount),  | 
153  | 0  |             State::Specialized(ref mut state) => state.combine(other_crc, other.amount),  | 
154  |  |         }  | 
155  | 0  |     }  | 
156  |  | }  | 
157  |  |  | 
158  |  | impl fmt::Debug for Hasher { | 
159  | 0  |     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 
160  | 0  |         f.debug_struct("crc32fast::Hasher").finish() | 
161  | 0  |     }  | 
162  |  | }  | 
163  |  |  | 
164  |  | impl Default for Hasher { | 
165  | 11.7k  |     fn default() -> Self { | 
166  | 11.7k  |         Self::new()  | 
167  | 11.7k  |     }  | 
168  |  | }  | 
169  |  |  | 
170  |  | impl hash::Hasher for Hasher { | 
171  | 0  |     fn write(&mut self, bytes: &[u8]) { | 
172  | 0  |         self.update(bytes)  | 
173  | 0  |     }  | 
174  |  |  | 
175  | 0  |     fn finish(&self) -> u64 { | 
176  | 0  |         u64::from(self.clone().finalize())  | 
177  | 0  |     }  | 
178  |  | }  | 
179  |  |  | 
180  |  | #[cfg(test)]  | 
181  |  | mod test { | 
182  |  |     use super::Hasher;  | 
183  |  |  | 
184  |  |     quickcheck::quickcheck! { | 
185  |  |         fn combine(bytes_1: Vec<u8>, bytes_2: Vec<u8>) -> bool { | 
186  |  |             let mut hash_a = Hasher::new();  | 
187  |  |             hash_a.update(&bytes_1);  | 
188  |  |             hash_a.update(&bytes_2);  | 
189  |  |             let mut hash_b = Hasher::new();  | 
190  |  |             hash_b.update(&bytes_2);  | 
191  |  |             let mut hash_c = Hasher::new();  | 
192  |  |             hash_c.update(&bytes_1);  | 
193  |  |             hash_c.combine(&hash_b);  | 
194  |  |  | 
195  |  |             hash_a.finalize() == hash_c.finalize()  | 
196  |  |         }  | 
197  |  |  | 
198  |  |         fn combine_from_len(bytes_1: Vec<u8>, bytes_2: Vec<u8>) -> bool { | 
199  |  |             let mut hash_a = Hasher::new();  | 
200  |  |             hash_a.update(&bytes_1);  | 
201  |  |  | 
202  |  |             let mut hash_b = Hasher::new();  | 
203  |  |             hash_b.update(&bytes_2);  | 
204  |  |  | 
205  |  |             let mut hash_ab = Hasher::new();  | 
206  |  |             hash_ab.update(&bytes_1);  | 
207  |  |             hash_ab.update(&bytes_2);  | 
208  |  |             let ab = hash_ab.finalize();  | 
209  |  |  | 
210  |  |             hash_a.combine(&hash_b);  | 
211  |  |             hash_a.finalize() == ab  | 
212  |  |         }  | 
213  |  |     }  | 
214  |  | }  |