//! # simd-adler32 //! //! A SIMD-accelerated Adler-32 hash algorithm implementation. //! //! ## Features //! //! - No dependencies //! - Support `no_std` (with `default-features = false`) //! - Runtime CPU feature detection (when `std` enabled) //! - Blazing fast performance on as many targets as possible (currently only x86 and x86_64) //! - Default to scalar implementation when simd not available //! //! ## Quick start //! //! > Cargo.toml //! //! ```toml //! [dependencies] //! simd-adler32 = "*" //! ``` //! //! > example.rs //! //! ```rust //! use simd_adler32::Adler32; //! //! let mut adler = Adler32::new(); //! adler.write(b"rust is pretty cool, man"); //! let hash = adler.finish(); //! //! println!("{}", hash); //! // 1921255656 //! ``` //! //! ## Feature flags //! //! * `std` - Enabled by default //! //! Enables std support, see [CPU Feature Detection](#cpu-feature-detection) for runtime //! detection support. //! * `nightly` //! //! Enables nightly features required for avx512 support. //! //! * `const-generics` - Enabled by default //! //! Enables const-generics support allowing for user-defined array hashing by value. See //! [`Adler32Hash`] for details. //! //! ## Support //! //! **CPU Features** //! //! | impl | arch | feature | //! | ---- | ---------------- | ------- | //! | ✅ | `x86`, `x86_64` | avx512 | //! | ✅ | `x86`, `x86_64` | avx2 | //! | ✅ | `x86`, `x86_64` | ssse3 | //! | ✅ | `x86`, `x86_64` | sse2 | //! | 🚧 | `arm`, `aarch64` | neon | //! | | `wasm32` | simd128 | //! //! **MSRV** `1.36.0`\*\* //! //! Minimum supported rust version is tested before a new version is published. [**] Feature //! `const-generics` needs to disabled to build on rustc versions `<1.51` which can be done //! by updating your dependency definition to the following. //! //! ## CPU Feature Detection //! simd-adler32 supports both runtime and compile time CPU feature detection using the //! `std::is_x86_feature_detected` macro when the `Adler32` struct is instantiated with //! the `new` fn. //! //! Without `std` feature enabled simd-adler32 falls back to compile time feature detection //! 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) //! for more information. //! //! Feature detection tries to use the fastest supported feature first. #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "nightly", feature(stdsimd, avx512_target_feature))] #[doc(hidden)] pub mod hash; #[doc(hidden)] pub mod imp; pub use hash::*; use imp::{get_imp, Adler32Imp}; /// An adler32 hash generator type. #[derive(Clone)] pub struct Adler32 { a: u16, b: u16, update: Adler32Imp, } impl Adler32 { /// Constructs a new `Adler32`. /// /// Potential overhead here due to runtime feature detection although in testing on 100k /// and 10k random byte arrays it was not really noticeable. /// /// # Examples /// ```rust /// use simd_adler32::Adler32; /// /// let mut adler = Adler32::new(); /// ``` pub fn new() -> Self { Default::default() } /// Constructs a new `Adler32` using existing checksum. /// /// Potential overhead here due to runtime feature detection although in testing on 100k /// and 10k random byte arrays it was not really noticeable. /// /// # Examples /// ```rust /// use simd_adler32::Adler32; /// /// let mut adler = Adler32::from_checksum(0xdeadbeaf); /// ``` pub fn from_checksum(checksum: u32) -> Self { Self { a: checksum as u16, b: (checksum >> 16) as u16, update: get_imp(), } } /// Computes hash for supplied data and stores results in internal state. pub fn write(&mut self, data: &[u8]) { let (a, b) = (self.update)(self.a, self.b, data); self.a = a; self.b = b; } /// Returns the hash value for the values written so far. /// /// Despite its name, the method does not reset the hasher’s internal state. Additional /// writes will continue from the current value. If you need to start a fresh hash /// value, you will have to use `reset`. pub fn finish(&self) -> u32 { (u32::from(self.b) << 16) | u32::from(self.a) } /// Resets the internal state. pub fn reset(&mut self) { self.a = 1; self.b = 0; } } /// Compute Adler-32 hash on `Adler32Hash` type. /// /// # Arguments /// * `hash` - A Adler-32 hash-able type. /// /// # Examples /// ```rust /// use simd_adler32::adler32; /// /// let hash = adler32(b"Adler-32"); /// println!("{}", hash); // 800813569 /// ``` pub fn adler32(hash: &H) -> u32 { hash.hash() } /// A Adler-32 hash-able type. pub trait Adler32Hash { /// Feeds this value into `Adler32`. fn hash(&self) -> u32; } impl Default for Adler32 { fn default() -> Self { Self { a: 1, b: 0, update: get_imp(), } } } #[cfg(feature = "std")] pub mod read { //! Reader-based hashing. //! //! # Example //! ```rust //! use std::io::Cursor; //! use simd_adler32::read::adler32; //! //! let mut reader = Cursor::new(b"Hello there"); //! let hash = adler32(&mut reader).unwrap(); //! //! println!("{}", hash) // 800813569 //! ``` use crate::Adler32; use std::io::{Read, Result}; /// Compute Adler-32 hash on reader until EOF. /// /// # Example /// ```rust /// use std::io::Cursor; /// use simd_adler32::read::adler32; /// /// let mut reader = Cursor::new(b"Hello there"); /// let hash = adler32(&mut reader).unwrap(); /// /// println!("{}", hash) // 800813569 /// ``` pub fn adler32(reader: &mut R) -> Result { let mut hash = Adler32::new(); let mut buf = [0; 4096]; loop { match reader.read(&mut buf) { Ok(0) => return Ok(hash.finish()), Ok(n) => { hash.write(&buf[..n]); } Err(err) => return Err(err), } } } } #[cfg(feature = "std")] pub mod bufread { //! BufRead-based hashing. //! //! Separate `BufRead` trait implemented to allow for custom buffer size optimization. //! //! # Example //! ```rust //! use std::io::{Cursor, BufReader}; //! use simd_adler32::bufread::adler32; //! //! let mut reader = Cursor::new(b"Hello there"); //! let mut reader = BufReader::new(reader); //! let hash = adler32(&mut reader).unwrap(); //! //! println!("{}", hash) // 800813569 //! ``` use crate::Adler32; use std::io::{BufRead, ErrorKind, Result}; /// Compute Adler-32 hash on buf reader until EOF. /// /// # Example /// ```rust /// use std::io::{Cursor, BufReader}; /// use simd_adler32::bufread::adler32; /// /// let mut reader = Cursor::new(b"Hello there"); /// let mut reader = BufReader::new(reader); /// let hash = adler32(&mut reader).unwrap(); /// /// println!("{}", hash) // 800813569 /// ``` pub fn adler32(reader: &mut R) -> Result { let mut hash = Adler32::new(); loop { let consumed = match reader.fill_buf() { Ok(buf) => { if buf.is_empty() { return Ok(hash.finish()); } hash.write(buf); buf.len() } Err(err) => match err.kind() { ErrorKind::Interrupted => continue, ErrorKind::UnexpectedEof => return Ok(hash.finish()), _ => return Err(err), }, }; reader.consume(consumed); } } } #[cfg(test)] mod tests { #[test] fn test_from_checksum() { let buf = b"rust is pretty cool man"; let sum = 0xdeadbeaf; let mut simd = super::Adler32::from_checksum(sum); let mut adler = adler::Adler32::from_checksum(sum); simd.write(buf); adler.write_slice(buf); let simd = simd.finish(); let scalar = adler.checksum(); assert_eq!(simd, scalar); } }