| Transpile a second crate, adler2, to test whether any of this generalises 5fdd5be nandithebull 14h ago | 1 | //@ args: run |
| 2 | // adler2 2.0.1. `algo.rs` is the crate's own file, byte-for-byte. |
| 3 | // This root carries `lib.rs`'s items (its `BufRead` reader needs std I/O |
| 4 | // and is left out) plus a driver, since the runner needs a `main`. |
| 5 | |
| 6 | mod algo; |
| 7 | |
| 8 | use core::hash::Hasher; |
| 9 | |
| 10 | #[derive(Debug, Copy, Clone)] |
| 11 | pub struct Adler32 { |
| 12 | a: u16, |
| 13 | b: u16, |
| 14 | } |
| 15 | |
| 16 | impl Adler32 { |
| 17 | /// Creates a new Adler-32 instance with default state. |
| 18 | #[inline] |
| 19 | pub fn new() -> Self { |
| 20 | Self::default() |
| 21 | } |
| 22 | |
| 23 | /// Creates an `Adler32` instance from a precomputed Adler-32 checksum. |
| 24 | /// |
| 25 | /// This allows resuming checksum calculation without having to keep the `Adler32` instance |
| 26 | /// around. |
| 27 | /// |
| 28 | /// # Example |
| 29 | /// |
| 30 | /// ``` |
| 31 | /// # use adler2::Adler32; |
| 32 | /// let parts = [ |
| 33 | /// "rust", |
| 34 | /// "acean", |
| 35 | /// ]; |
| 36 | /// let whole = adler2::adler32_slice(b"rustacean"); |
| 37 | /// |
| 38 | /// let mut sum = Adler32::new(); |
| 39 | /// sum.write_slice(parts[0].as_bytes()); |
| 40 | /// let partial = sum.checksum(); |
| 41 | /// |
| 42 | /// // ...later |
| 43 | /// |
| 44 | /// let mut sum = Adler32::from_checksum(partial); |
| 45 | /// sum.write_slice(parts[1].as_bytes()); |
| 46 | /// assert_eq!(sum.checksum(), whole); |
| 47 | /// ``` |
| 48 | #[inline] |
| 49 | pub const fn from_checksum(sum: u32) -> Self { |
| 50 | Adler32 { |
| 51 | a: sum as u16, |
| 52 | b: (sum >> 16) as u16, |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | /// Returns the calculated checksum at this point in time. |
| 57 | #[inline] |
| 58 | pub fn checksum(&self) -> u32 { |
| 59 | (u32::from(self.b) << 16) | u32::from(self.a) |
| 60 | } |
| 61 | |
| 62 | /// Adds `bytes` to the checksum calculation. |
| 63 | /// |
| 64 | /// If efficiency matters, this should be called with Byte slices that contain at least a few |
| 65 | /// thousand Bytes. |
| 66 | pub fn write_slice(&mut self, bytes: &[u8]) { |
| 67 | self.compute(bytes); |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | impl Default for Adler32 { |
| 72 | #[inline] |
| 73 | fn default() -> Self { |
| 74 | Adler32 { a: 1, b: 0 } |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | impl Hasher for Adler32 { |
| 79 | #[inline] |
| 80 | fn finish(&self) -> u64 { |
| 81 | u64::from(self.checksum()) |
| 82 | } |
| 83 | |
| 84 | fn write(&mut self, bytes: &[u8]) { |
| 85 | self.write_slice(bytes); |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | /// Calculates the Adler-32 checksum of a byte slice. |
| 90 | /// |
| 91 | /// This is a convenience function around the [`Adler32`] type. |
| 92 | /// |
| 93 | /// [`Adler32`]: struct.Adler32.html |
| 94 | pub fn adler32_slice(data: &[u8]) -> u32 { |
| 95 | let mut h = Adler32::new(); |
| 96 | h.write_slice(data); |
| 97 | h.checksum() |
| 98 | } |
| 99 | |
| 100 | fn main() { |
| 101 | // Known vectors: the empty input, "Wikipedia", and simple patterns. |
| 102 | println!("{:08x}", adler32_slice(b"")); |
| 103 | println!("{:08x}", adler32_slice(b"Wikipedia")); |
| 104 | println!("{:08x}", adler32_slice(b"a")); |
| 105 | println!("{:08x}", adler32_slice(b"abc")); |
| 106 | |
| 107 | // Every single byte. |
| 108 | let mut i: u32 = 0; |
| 109 | while i < 256 { |
| 110 | let one: [u8; 1] = [i as u8]; |
| 111 | print!("{:08x} ", adler32_slice(&one)); |
| 112 | i += 1; |
| 113 | } |
| 114 | println!(""); |
| 115 | |
| 116 | // Lengths across the 4-byte unrolling boundary and well past it, so the |
| 117 | // chunked path, the remainder path and the serial tail are all exercised. |
| 118 | let mut n: usize = 0; |
| 119 | while n <= 600 { |
| 120 | let mut buf: Vec<u8> = vec![0u8; n]; |
| 121 | let mut j: usize = 0; |
| 122 | while j < n { |
| 123 | buf[j] = ((j * 31 + 7) % 256) as u8; |
| 124 | j += 1; |
| 125 | } |
| 126 | print!("{:08x} ", adler32_slice(&buf)); |
| 127 | n += 1; |
| 128 | } |
| 129 | println!(""); |
| 130 | |
| 131 | // Incremental writes must equal one write of the concatenation. |
| 132 | let mut data: Vec<u8> = vec![0u8; 1000]; |
| 133 | let mut k: usize = 0; |
| 134 | while k < 1000 { |
| 135 | data[k] = ((k * 97 + 13) % 256) as u8; |
| 136 | k += 1; |
| 137 | } |
| 138 | let mut split: usize = 0; |
| 139 | while split <= 1000 { |
| 140 | let mut h = Adler32::new(); |
| 141 | h.write_slice(&data[..split]); |
| 142 | h.write_slice(&data[split..]); |
| 143 | print!("{:08x} ", h.checksum()); |
| 144 | split += 7; |
| 145 | } |
| 146 | println!(""); |
| 147 | println!("{:08x}", adler32_slice(&data)); |
| 148 | } |