/rust/registry/src/index.crates.io-6f17d22bba15001f/simd-adler32-0.3.7/src/lib.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! # simd-adler32 |
2 | | //! |
3 | | //! A SIMD-accelerated Adler-32 hash algorithm implementation. |
4 | | //! |
5 | | //! ## Features |
6 | | //! |
7 | | //! - No dependencies |
8 | | //! - Support `no_std` (with `default-features = false`) |
9 | | //! - Runtime CPU feature detection (when `std` enabled) |
10 | | //! - Blazing fast performance on as many targets as possible (currently only x86 and x86_64) |
11 | | //! - Default to scalar implementation when simd not available |
12 | | //! |
13 | | //! ## Quick start |
14 | | //! |
15 | | //! > Cargo.toml |
16 | | //! |
17 | | //! ```toml |
18 | | //! [dependencies] |
19 | | //! simd-adler32 = "*" |
20 | | //! ``` |
21 | | //! |
22 | | //! > example.rs |
23 | | //! |
24 | | //! ```rust |
25 | | //! use simd_adler32::Adler32; |
26 | | //! |
27 | | //! let mut adler = Adler32::new(); |
28 | | //! adler.write(b"rust is pretty cool, man"); |
29 | | //! let hash = adler.finish(); |
30 | | //! |
31 | | //! println!("{}", hash); |
32 | | //! // 1921255656 |
33 | | //! ``` |
34 | | //! |
35 | | //! ## Feature flags |
36 | | //! |
37 | | //! * `std` - Enabled by default |
38 | | //! |
39 | | //! Enables std support, see [CPU Feature Detection](#cpu-feature-detection) for runtime |
40 | | //! detection support. |
41 | | //! * `nightly` |
42 | | //! |
43 | | //! Enables nightly features required for avx512 support. |
44 | | //! |
45 | | //! * `const-generics` - Enabled by default |
46 | | //! |
47 | | //! Enables const-generics support allowing for user-defined array hashing by value. See |
48 | | //! [`Adler32Hash`] for details. |
49 | | //! |
50 | | //! ## Support |
51 | | //! |
52 | | //! **CPU Features** |
53 | | //! |
54 | | //! | impl | arch | feature | |
55 | | //! | ---- | ---------------- | ------- | |
56 | | //! | ✅ | `x86`, `x86_64` | avx512 | |
57 | | //! | ✅ | `x86`, `x86_64` | avx2 | |
58 | | //! | ✅ | `x86`, `x86_64` | ssse3 | |
59 | | //! | ✅ | `x86`, `x86_64` | sse2 | |
60 | | //! | 🚧 | `arm`, `aarch64` | neon | |
61 | | //! | | `wasm32` | simd128 | |
62 | | //! |
63 | | //! **MSRV** `1.36.0`\*\* |
64 | | //! |
65 | | //! Minimum supported rust version is tested before a new version is published. [**] Feature |
66 | | //! `const-generics` needs to disabled to build on rustc versions `<1.51` which can be done |
67 | | //! by updating your dependency definition to the following. |
68 | | //! |
69 | | //! ## CPU Feature Detection |
70 | | //! simd-adler32 supports both runtime and compile time CPU feature detection using the |
71 | | //! `std::is_x86_feature_detected` macro when the `Adler32` struct is instantiated with |
72 | | //! the `new` fn. |
73 | | //! |
74 | | //! Without `std` feature enabled simd-adler32 falls back to compile time feature detection |
75 | | //! using `target-feature` or `target-cpu` flags supplied to rustc. See [https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html](https://rust-lang.github.io/packed_simd/perf-guide/target-feature/rustflags.html) |
76 | | //! for more information. |
77 | | //! |
78 | | //! Feature detection tries to use the fastest supported feature first. |
79 | | #![cfg_attr(not(feature = "std"), no_std)] |
80 | | #![cfg_attr(feature = "nightly", feature(stdsimd, avx512_target_feature))] |
81 | | |
82 | | #[doc(hidden)] |
83 | | pub mod hash; |
84 | | #[doc(hidden)] |
85 | | pub mod imp; |
86 | | |
87 | | pub use hash::*; |
88 | | use imp::{get_imp, Adler32Imp}; |
89 | | |
90 | | /// An adler32 hash generator type. |
91 | | #[derive(Clone)] |
92 | | pub struct Adler32 { |
93 | | a: u16, |
94 | | b: u16, |
95 | | update: Adler32Imp, |
96 | | } |
97 | | |
98 | | impl Adler32 { |
99 | | /// Constructs a new `Adler32`. |
100 | | /// |
101 | | /// Potential overhead here due to runtime feature detection although in testing on 100k |
102 | | /// and 10k random byte arrays it was not really noticeable. |
103 | | /// |
104 | | /// # Examples |
105 | | /// ```rust |
106 | | /// use simd_adler32::Adler32; |
107 | | /// |
108 | | /// let mut adler = Adler32::new(); |
109 | | /// ``` |
110 | 0 | pub fn new() -> Self { |
111 | 0 | Default::default() |
112 | 0 | } |
113 | | |
114 | | /// Constructs a new `Adler32` using existing checksum. |
115 | | /// |
116 | | /// Potential overhead here due to runtime feature detection although in testing on 100k |
117 | | /// and 10k random byte arrays it was not really noticeable. |
118 | | /// |
119 | | /// # Examples |
120 | | /// ```rust |
121 | | /// use simd_adler32::Adler32; |
122 | | /// |
123 | | /// let mut adler = Adler32::from_checksum(0xdeadbeaf); |
124 | | /// ``` |
125 | 0 | pub fn from_checksum(checksum: u32) -> Self { |
126 | 0 | Self { |
127 | 0 | a: checksum as u16, |
128 | 0 | b: (checksum >> 16) as u16, |
129 | 0 | update: get_imp(), |
130 | 0 | } |
131 | 0 | } |
132 | | |
133 | | /// Computes hash for supplied data and stores results in internal state. |
134 | 0 | pub fn write(&mut self, data: &[u8]) { |
135 | 0 | let (a, b) = (self.update)(self.a, self.b, data); |
136 | 0 |
|
137 | 0 | self.a = a; |
138 | 0 | self.b = b; |
139 | 0 | } |
140 | | |
141 | | /// Returns the hash value for the values written so far. |
142 | | /// |
143 | | /// Despite its name, the method does not reset the hasher’s internal state. Additional |
144 | | /// writes will continue from the current value. If you need to start a fresh hash |
145 | | /// value, you will have to use `reset`. |
146 | 0 | pub fn finish(&self) -> u32 { |
147 | 0 | (u32::from(self.b) << 16) | u32::from(self.a) |
148 | 0 | } |
149 | | |
150 | | /// Resets the internal state. |
151 | 0 | pub fn reset(&mut self) { |
152 | 0 | self.a = 1; |
153 | 0 | self.b = 0; |
154 | 0 | } |
155 | | } |
156 | | |
157 | | /// Compute Adler-32 hash on `Adler32Hash` type. |
158 | | /// |
159 | | /// # Arguments |
160 | | /// * `hash` - A Adler-32 hash-able type. |
161 | | /// |
162 | | /// # Examples |
163 | | /// ```rust |
164 | | /// use simd_adler32::adler32; |
165 | | /// |
166 | | /// let hash = adler32(b"Adler-32"); |
167 | | /// println!("{}", hash); // 800813569 |
168 | | /// ``` |
169 | 0 | pub fn adler32<H: Adler32Hash>(hash: &H) -> u32 { |
170 | 0 | hash.hash() |
171 | 0 | } |
172 | | |
173 | | /// A Adler-32 hash-able type. |
174 | | pub trait Adler32Hash { |
175 | | /// Feeds this value into `Adler32`. |
176 | | fn hash(&self) -> u32; |
177 | | } |
178 | | |
179 | | impl Default for Adler32 { |
180 | 0 | fn default() -> Self { |
181 | 0 | Self { |
182 | 0 | a: 1, |
183 | 0 | b: 0, |
184 | 0 | update: get_imp(), |
185 | 0 | } |
186 | 0 | } |
187 | | } |
188 | | |
189 | | #[cfg(feature = "std")] |
190 | | pub mod read { |
191 | | //! Reader-based hashing. |
192 | | //! |
193 | | //! # Example |
194 | | //! ```rust |
195 | | //! use std::io::Cursor; |
196 | | //! use simd_adler32::read::adler32; |
197 | | //! |
198 | | //! let mut reader = Cursor::new(b"Hello there"); |
199 | | //! let hash = adler32(&mut reader).unwrap(); |
200 | | //! |
201 | | //! println!("{}", hash) // 800813569 |
202 | | //! ``` |
203 | | use crate::Adler32; |
204 | | use std::io::{Read, Result}; |
205 | | |
206 | | /// Compute Adler-32 hash on reader until EOF. |
207 | | /// |
208 | | /// # Example |
209 | | /// ```rust |
210 | | /// use std::io::Cursor; |
211 | | /// use simd_adler32::read::adler32; |
212 | | /// |
213 | | /// let mut reader = Cursor::new(b"Hello there"); |
214 | | /// let hash = adler32(&mut reader).unwrap(); |
215 | | /// |
216 | | /// println!("{}", hash) // 800813569 |
217 | | /// ``` |
218 | | pub fn adler32<R: Read>(reader: &mut R) -> Result<u32> { |
219 | | let mut hash = Adler32::new(); |
220 | | let mut buf = [0; 4096]; |
221 | | |
222 | | loop { |
223 | | match reader.read(&mut buf) { |
224 | | Ok(0) => return Ok(hash.finish()), |
225 | | Ok(n) => { |
226 | | hash.write(&buf[..n]); |
227 | | } |
228 | | Err(err) => return Err(err), |
229 | | } |
230 | | } |
231 | | } |
232 | | } |
233 | | |
234 | | #[cfg(feature = "std")] |
235 | | pub mod bufread { |
236 | | //! BufRead-based hashing. |
237 | | //! |
238 | | //! Separate `BufRead` trait implemented to allow for custom buffer size optimization. |
239 | | //! |
240 | | //! # Example |
241 | | //! ```rust |
242 | | //! use std::io::{Cursor, BufReader}; |
243 | | //! use simd_adler32::bufread::adler32; |
244 | | //! |
245 | | //! let mut reader = Cursor::new(b"Hello there"); |
246 | | //! let mut reader = BufReader::new(reader); |
247 | | //! let hash = adler32(&mut reader).unwrap(); |
248 | | //! |
249 | | //! println!("{}", hash) // 800813569 |
250 | | //! ``` |
251 | | use crate::Adler32; |
252 | | use std::io::{BufRead, ErrorKind, Result}; |
253 | | |
254 | | /// Compute Adler-32 hash on buf reader until EOF. |
255 | | /// |
256 | | /// # Example |
257 | | /// ```rust |
258 | | /// use std::io::{Cursor, BufReader}; |
259 | | /// use simd_adler32::bufread::adler32; |
260 | | /// |
261 | | /// let mut reader = Cursor::new(b"Hello there"); |
262 | | /// let mut reader = BufReader::new(reader); |
263 | | /// let hash = adler32(&mut reader).unwrap(); |
264 | | /// |
265 | | /// println!("{}", hash) // 800813569 |
266 | | /// ``` |
267 | | pub fn adler32<R: BufRead>(reader: &mut R) -> Result<u32> { |
268 | | let mut hash = Adler32::new(); |
269 | | |
270 | | loop { |
271 | | let consumed = match reader.fill_buf() { |
272 | | Ok(buf) => { |
273 | | if buf.is_empty() { |
274 | | return Ok(hash.finish()); |
275 | | } |
276 | | |
277 | | hash.write(buf); |
278 | | buf.len() |
279 | | } |
280 | | Err(err) => match err.kind() { |
281 | | ErrorKind::Interrupted => continue, |
282 | | ErrorKind::UnexpectedEof => return Ok(hash.finish()), |
283 | | _ => return Err(err), |
284 | | }, |
285 | | }; |
286 | | |
287 | | reader.consume(consumed); |
288 | | } |
289 | | } |
290 | | } |
291 | | |
292 | | #[cfg(test)] |
293 | | mod tests { |
294 | | #[test] |
295 | | fn test_from_checksum() { |
296 | | let buf = b"rust is pretty cool man"; |
297 | | let sum = 0xdeadbeaf; |
298 | | |
299 | | let mut simd = super::Adler32::from_checksum(sum); |
300 | | let mut adler = adler::Adler32::from_checksum(sum); |
301 | | |
302 | | simd.write(buf); |
303 | | adler.write_slice(buf); |
304 | | |
305 | | let simd = simd.finish(); |
306 | | let scalar = adler.checksum(); |
307 | | |
308 | | assert_eq!(simd, scalar); |
309 | | } |
310 | | } |