//@ args: run // adler2 2.0.1. `algo.rs` is the crate's own file, byte-for-byte. // This root carries `lib.rs`'s items (its `BufRead` reader needs std I/O // and is left out) plus a driver, since the runner needs a `main`. mod algo; use core::hash::Hasher; #[derive(Debug, Copy, Clone)] pub struct Adler32 { a: u16, b: u16, } impl Adler32 { /// Creates a new Adler-32 instance with default state. #[inline] pub fn new() -> Self { Self::default() } /// Creates an `Adler32` instance from a precomputed Adler-32 checksum. /// /// This allows resuming checksum calculation without having to keep the `Adler32` instance /// around. /// /// # Example /// /// ``` /// # use adler2::Adler32; /// let parts = [ /// "rust", /// "acean", /// ]; /// let whole = adler2::adler32_slice(b"rustacean"); /// /// let mut sum = Adler32::new(); /// sum.write_slice(parts[0].as_bytes()); /// let partial = sum.checksum(); /// /// // ...later /// /// let mut sum = Adler32::from_checksum(partial); /// sum.write_slice(parts[1].as_bytes()); /// assert_eq!(sum.checksum(), whole); /// ``` #[inline] pub const fn from_checksum(sum: u32) -> Self { Adler32 { a: sum as u16, b: (sum >> 16) as u16, } } /// Returns the calculated checksum at this point in time. #[inline] pub fn checksum(&self) -> u32 { (u32::from(self.b) << 16) | u32::from(self.a) } /// Adds `bytes` to the checksum calculation. /// /// If efficiency matters, this should be called with Byte slices that contain at least a few /// thousand Bytes. pub fn write_slice(&mut self, bytes: &[u8]) { self.compute(bytes); } } impl Default for Adler32 { #[inline] fn default() -> Self { Adler32 { a: 1, b: 0 } } } impl Hasher for Adler32 { #[inline] fn finish(&self) -> u64 { u64::from(self.checksum()) } fn write(&mut self, bytes: &[u8]) { self.write_slice(bytes); } } /// Calculates the Adler-32 checksum of a byte slice. /// /// This is a convenience function around the [`Adler32`] type. /// /// [`Adler32`]: struct.Adler32.html pub fn adler32_slice(data: &[u8]) -> u32 { let mut h = Adler32::new(); h.write_slice(data); h.checksum() } fn main() { // Known vectors: the empty input, "Wikipedia", and simple patterns. println!("{:08x}", adler32_slice(b"")); println!("{:08x}", adler32_slice(b"Wikipedia")); println!("{:08x}", adler32_slice(b"a")); println!("{:08x}", adler32_slice(b"abc")); // Every single byte. let mut i: u32 = 0; while i < 256 { let one: [u8; 1] = [i as u8]; print!("{:08x} ", adler32_slice(&one)); i += 1; } println!(""); // Lengths across the 4-byte unrolling boundary and well past it, so the // chunked path, the remainder path and the serial tail are all exercised. let mut n: usize = 0; while n <= 600 { let mut buf: Vec = vec![0u8; n]; let mut j: usize = 0; while j < n { buf[j] = ((j * 31 + 7) % 256) as u8; j += 1; } print!("{:08x} ", adler32_slice(&buf)); n += 1; } println!(""); // Incremental writes must equal one write of the concatenation. let mut data: Vec = vec![0u8; 1000]; let mut k: usize = 0; while k < 1000 { data[k] = ((k * 97 + 13) % 256) as u8; k += 1; } let mut split: usize = 0; while split <= 1000 { let mut h = Adler32::new(); h.write_slice(&data[..split]); h.write_slice(&data[split..]); print!("{:08x} ", h.checksum()); split += 7; } println!(""); println!("{:08x}", adler32_slice(&data)); }