#![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};
#[derive(Clone)]
pub struct Adler32 {
a: u16,
b: u16,
update: Adler32Imp,
}
impl Adler32 {
pub fn new() -> Self {
Default::default()
}
pub fn from_checksum(checksum: u32) -> Self {
Self {
a: checksum as u16,
b: (checksum >> 16) as u16,
update: get_imp(),
}
}
pub fn write(&mut self, data: &[u8]) {
let (a, b) = (self.update)(self.a, self.b, data);
self.a = a;
self.b = b;
}
pub fn finish(&self) -> u32 {
(u32::from(self.b) << 16) | u32::from(self.a)
}
pub fn reset(&mut self) {
self.a = 1;
self.b = 0;
}
}
pub fn adler32<H: Adler32Hash>(hash: &H) -> u32 {
hash.hash()
}
pub trait Adler32Hash {
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 {
use crate::Adler32;
use std::io::{Read, Result};
pub fn adler32<R: Read>(reader: &mut R) -> Result<u32> {
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 {
use crate::Adler32;
use std::io::{BufRead, ErrorKind, Result};
pub fn adler32<R: BufRead>(reader: &mut R) -> Result<u32> {
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);
}
}