/rust/registry/src/index.crates.io-1949cf8c6b5b557f/simd-adler32-0.3.8/src/lib.rs
Line | Count | Source |
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( |
81 | | all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64")), |
82 | | feature(stdarch_x86_avx512, avx512_target_feature) |
83 | | )] |
84 | | #![cfg_attr( |
85 | | all( |
86 | | feature = "nightly", |
87 | | target_arch = "wasm64", |
88 | | target_feature = "simd128" |
89 | | ), |
90 | | feature(simd_wasm64) |
91 | | )] |
92 | | |
93 | | #[doc(hidden)] |
94 | | pub mod hash; |
95 | | #[doc(hidden)] |
96 | | pub mod imp; |
97 | | |
98 | | pub use hash::*; |
99 | | use imp::{get_imp, Adler32Imp}; |
100 | | |
101 | | /// An adler32 hash generator type. |
102 | | #[derive(Clone)] |
103 | | pub struct Adler32 { |
104 | | a: u16, |
105 | | b: u16, |
106 | | update: Adler32Imp, |
107 | | } |
108 | | |
109 | | impl Adler32 { |
110 | | /// Constructs a new `Adler32`. |
111 | | /// |
112 | | /// Potential overhead here due to runtime feature detection although in testing on 100k |
113 | | /// and 10k random byte arrays it was not really noticeable. |
114 | | /// |
115 | | /// # Examples |
116 | | /// ```rust |
117 | | /// use simd_adler32::Adler32; |
118 | | /// |
119 | | /// let mut adler = Adler32::new(); |
120 | | /// ``` |
121 | 0 | pub fn new() -> Self { |
122 | 0 | Default::default() |
123 | 0 | } |
124 | | |
125 | | /// Constructs a new `Adler32` using existing checksum. |
126 | | /// |
127 | | /// Potential overhead here due to runtime feature detection although in testing on 100k |
128 | | /// and 10k random byte arrays it was not really noticeable. |
129 | | /// |
130 | | /// # Examples |
131 | | /// ```rust |
132 | | /// use simd_adler32::Adler32; |
133 | | /// |
134 | | /// let mut adler = Adler32::from_checksum(0xdeadbeaf); |
135 | | /// ``` |
136 | 0 | pub fn from_checksum(checksum: u32) -> Self { |
137 | 0 | Self { |
138 | 0 | a: checksum as u16, |
139 | 0 | b: (checksum >> 16) as u16, |
140 | 0 | update: get_imp(), |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | /// Computes hash for supplied data and stores results in internal state. |
145 | 0 | pub fn write(&mut self, data: &[u8]) { |
146 | 0 | let (a, b) = (self.update)(self.a, self.b, data); |
147 | | |
148 | 0 | self.a = a; |
149 | 0 | self.b = b; |
150 | 0 | } |
151 | | |
152 | | /// Returns the hash value for the values written so far. |
153 | | /// |
154 | | /// Despite its name, the method does not reset the hasher’s internal state. Additional |
155 | | /// writes will continue from the current value. If you need to start a fresh hash |
156 | | /// value, you will have to use `reset`. |
157 | 0 | pub fn finish(&self) -> u32 { |
158 | 0 | (u32::from(self.b) << 16) | u32::from(self.a) |
159 | 0 | } |
160 | | |
161 | | /// Resets the internal state. |
162 | 0 | pub fn reset(&mut self) { |
163 | 0 | self.a = 1; |
164 | 0 | self.b = 0; |
165 | 0 | } |
166 | | } |
167 | | |
168 | | /// Compute Adler-32 hash on `Adler32Hash` type. |
169 | | /// |
170 | | /// # Arguments |
171 | | /// * `hash` - A Adler-32 hash-able type. |
172 | | /// |
173 | | /// # Examples |
174 | | /// ```rust |
175 | | /// use simd_adler32::adler32; |
176 | | /// |
177 | | /// let hash = adler32(b"Adler-32"); |
178 | | /// println!("{}", hash); // 800813569 |
179 | | /// ``` |
180 | 0 | pub fn adler32<H: Adler32Hash>(hash: &H) -> u32 { |
181 | 0 | hash.hash() |
182 | 0 | } |
183 | | |
184 | | /// A Adler-32 hash-able type. |
185 | | pub trait Adler32Hash { |
186 | | /// Feeds this value into `Adler32`. |
187 | | fn hash(&self) -> u32; |
188 | | } |
189 | | |
190 | | impl Default for Adler32 { |
191 | 0 | fn default() -> Self { |
192 | 0 | Self { |
193 | 0 | a: 1, |
194 | 0 | b: 0, |
195 | 0 | update: get_imp(), |
196 | 0 | } |
197 | 0 | } |
198 | | } |
199 | | |
200 | | #[cfg(feature = "std")] |
201 | | pub mod read { |
202 | | //! Reader-based hashing. |
203 | | //! |
204 | | //! # Example |
205 | | //! ```rust |
206 | | //! use std::io::Cursor; |
207 | | //! use simd_adler32::read::adler32; |
208 | | //! |
209 | | //! let mut reader = Cursor::new(b"Hello there"); |
210 | | //! let hash = adler32(&mut reader).unwrap(); |
211 | | //! |
212 | | //! println!("{}", hash) // 800813569 |
213 | | //! ``` |
214 | | use crate::Adler32; |
215 | | use std::io::{Read, Result}; |
216 | | |
217 | | /// Compute Adler-32 hash on reader until EOF. |
218 | | /// |
219 | | /// # Example |
220 | | /// ```rust |
221 | | /// use std::io::Cursor; |
222 | | /// use simd_adler32::read::adler32; |
223 | | /// |
224 | | /// let mut reader = Cursor::new(b"Hello there"); |
225 | | /// let hash = adler32(&mut reader).unwrap(); |
226 | | /// |
227 | | /// println!("{}", hash) // 800813569 |
228 | | /// ``` |
229 | | pub fn adler32<R: Read>(reader: &mut R) -> Result<u32> { |
230 | | let mut hash = Adler32::new(); |
231 | | let mut buf = [0; 4096]; |
232 | | |
233 | | loop { |
234 | | match reader.read(&mut buf) { |
235 | | Ok(0) => return Ok(hash.finish()), |
236 | | Ok(n) => { |
237 | | hash.write(&buf[..n]); |
238 | | } |
239 | | Err(err) => return Err(err), |
240 | | } |
241 | | } |
242 | | } |
243 | | } |
244 | | |
245 | | #[cfg(feature = "std")] |
246 | | pub mod bufread { |
247 | | //! BufRead-based hashing. |
248 | | //! |
249 | | //! Separate `BufRead` trait implemented to allow for custom buffer size optimization. |
250 | | //! |
251 | | //! # Example |
252 | | //! ```rust |
253 | | //! use std::io::{Cursor, BufReader}; |
254 | | //! use simd_adler32::bufread::adler32; |
255 | | //! |
256 | | //! let mut reader = Cursor::new(b"Hello there"); |
257 | | //! let mut reader = BufReader::new(reader); |
258 | | //! let hash = adler32(&mut reader).unwrap(); |
259 | | //! |
260 | | //! println!("{}", hash) // 800813569 |
261 | | //! ``` |
262 | | use crate::Adler32; |
263 | | use std::io::{BufRead, ErrorKind, Result}; |
264 | | |
265 | | /// Compute Adler-32 hash on buf reader until EOF. |
266 | | /// |
267 | | /// # Example |
268 | | /// ```rust |
269 | | /// use std::io::{Cursor, BufReader}; |
270 | | /// use simd_adler32::bufread::adler32; |
271 | | /// |
272 | | /// let mut reader = Cursor::new(b"Hello there"); |
273 | | /// let mut reader = BufReader::new(reader); |
274 | | /// let hash = adler32(&mut reader).unwrap(); |
275 | | /// |
276 | | /// println!("{}", hash) // 800813569 |
277 | | /// ``` |
278 | | pub fn adler32<R: BufRead>(reader: &mut R) -> Result<u32> { |
279 | | let mut hash = Adler32::new(); |
280 | | |
281 | | loop { |
282 | | let consumed = match reader.fill_buf() { |
283 | | Ok(buf) => { |
284 | | if buf.is_empty() { |
285 | | return Ok(hash.finish()); |
286 | | } |
287 | | |
288 | | hash.write(buf); |
289 | | buf.len() |
290 | | } |
291 | | Err(err) => match err.kind() { |
292 | | ErrorKind::Interrupted => continue, |
293 | | ErrorKind::UnexpectedEof => return Ok(hash.finish()), |
294 | | _ => return Err(err), |
295 | | }, |
296 | | }; |
297 | | |
298 | | reader.consume(consumed); |
299 | | } |
300 | | } |
301 | | } |
302 | | |
303 | | #[cfg(test)] |
304 | | mod tests { |
305 | | #[test] |
306 | | fn test_from_checksum() { |
307 | | let buf = b"rust is pretty cool man"; |
308 | | let sum = 0xdeadbeaf; |
309 | | |
310 | | let mut simd = super::Adler32::from_checksum(sum); |
311 | | let mut adler = adler::Adler32::from_checksum(sum); |
312 | | |
313 | | simd.write(buf); |
314 | | adler.write_slice(buf); |
315 | | |
316 | | let simd = simd.finish(); |
317 | | let scalar = adler.checksum(); |
318 | | |
319 | | assert_eq!(simd, scalar); |
320 | | } |
321 | | } |