use binrw::binrw;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(test)]
mod tests;
#[binrw]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(transparent)]
pub struct Checksum {
inner: u32,
}
impl Checksum {
fn from_bytes<F>(buf: &[u8], f: F) -> Self
where
F: Fn([u8; 2]) -> u16,
{
let mut sum: u16 = 0;
let mut inv_sum: u16 = 0;
for term in buf.chunks_exact(size_of::<u16>()).map(|c| f([c[0], c[1]])) {
sum = sum.wrapping_add(term);
inv_sum = inv_sum.wrapping_add(!term);
}
Self {
inner: ((sum as u32) << u16::BITS) | inv_sum as u32,
}
}
pub fn from_be_bytes(buf: &[u8]) -> Self {
Self::from_bytes(buf, u16::from_be_bytes)
}
pub fn from_le_bytes(buf: &[u8]) -> Self {
Self::from_bytes(buf, u16::from_le_bytes)
}
pub const fn from_raw(checksum: u32) -> Self {
Self { inner: checksum }
}
pub const fn into_raw(self) -> u32 {
self.inner
}
}