#[derive(Clone, Debug)]
pub struct Checksum {
acc: u64,
}
impl Checksum {
#[inline]
#[must_use]
pub fn new() -> Self {
Self { acc: 0 }
}
#[inline]
pub fn update(&mut self, data: &[u8]) {
checksum_no_fold(data, &mut self.acc);
}
#[inline]
#[must_use]
pub fn finalize(self) -> u16 {
fold(self.acc)
}
#[inline]
pub fn reset(&mut self) {
self.acc = 0;
}
}
impl Default for Checksum {
fn default() -> Self {
Self::new()
}
}
fn checksum_no_fold(b: &[u8], acc: &mut u64) {
let mut ac = *acc;
let mut b = b;
while b.len() >= 128 {
while b.len() >= 4 {
let num = u32::from_ne_bytes([b[0], b[1], b[2], b[3]]) as u64;
ac = ac.wrapping_add(num);
b = &b[4..];
}
}
while b.len() >= 64 {
while b.len() >= 4 {
let num = u32::from_ne_bytes([b[0], b[1], b[2], b[3]]) as u64;
ac = ac.wrapping_add(num);
b = &b[4..];
}
}
while b.len() >= 4 {
let num = u32::from_ne_bytes([b[0], b[1], b[2], b[3]]) as u64;
ac = ac.wrapping_add(num);
b = &b[4..];
}
if b.len() >= 2 {
let num = u16::from_ne_bytes([b[0], b[1]]) as u64;
ac = ac.wrapping_add(num);
b = &b[2..];
}
if !b.is_empty() {
ac = ac.wrapping_add(b[0] as u64);
}
*acc = ac;
}
#[inline]
fn fold(acc: u64) -> u16 {
let mut sum = acc;
sum = (sum >> 32) + (sum & 0xffff_ffff);
sum = (sum >> 16) + (sum & 0xffff);
sum += sum >> 16;
let result = !(sum as u16);
if cfg!(target_endian = "little") {
result.swap_bytes()
} else {
result
}
}