Coverage Report

Created: 2025-07-11 06:50

/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
}