Coverage Report

Created: 2026-07-16 07:16

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