libmhash 0.2.1

A file hashing library that can do multiple hashes for multile files at the same time.
Documentation
use std::mem::size_of;

use crate::{paranoid_hash::Hasher, Error, Result};

#[derive(Clone, Debug, Default)]
pub struct CRC32 {
    state: crc32fast::Hasher,
    is_done: bool,
    digest: [u8; 4],
}

#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct CRC32C {
    state: u32,
    is_done: bool,
    digest: [u8; 4],
}

impl CRC32 {
    pub const BLOCK_SIZE: usize = 1;
    pub const DIGEST_SIZE: usize = size_of::<u32>();

    pub fn new() -> Self {
        Self {
            state: crc32fast::Hasher::new(),
            digest: [0; 4],
            is_done: false,
        }
    }
}

impl Hasher for CRC32 {
    fn update(&mut self, data: &[u8]) -> Result<()> {
        if self.is_done {
            return Err(Error::UpdatingAfterFinished);
        }

        self.state.update(data);

        Ok(())
    }

    fn update_last(&mut self, data: &[u8]) -> Result<()> {
        self.update(data)?;

        self.digest = self.state.clone().finalize().to_be_bytes();

        self.is_done = true;

        Ok(())
    }

    fn digest(&self) -> Result<&[u8]> {
        if !self.is_done {
            return Err(Error::NotFinished);
        }

        Ok(&self.digest)
    }

    fn reset(&mut self) {
        *self = Self::new();
    }

    fn block_size(&self) -> usize {
        Self::BLOCK_SIZE
    }

    fn digest_size(&self) -> usize {
        Self::DIGEST_SIZE
    }
}

impl CRC32C {
    pub const BLOCK_SIZE: usize = 1;
    pub const DIGEST_SIZE: usize = size_of::<u32>();

    pub const fn new() -> Self {
        Self {
            state: 0,
            digest: [0; 4],
            is_done: false,
        }
    }
}

impl Hasher for CRC32C {
    fn update(&mut self, data: &[u8]) -> Result<()> {
        if self.is_done {
            return Err(Error::UpdatingAfterFinished);
        }

        self.state = crc32c::crc32c_append(self.state, data);

        Ok(())
    }

    fn update_last(&mut self, data: &[u8]) -> Result<()> {
        self.update(data)?;

        self.digest = self.state.to_be_bytes();

        self.is_done = true;

        Ok(())
    }

    fn digest(&self) -> Result<&[u8]> {
        if !self.is_done {
            return Err(Error::NotFinished);
        }

        Ok(&self.digest)
    }

    fn reset(&mut self) {
        *self = Self::new();
    }

    fn block_size(&self) -> usize {
        Self::BLOCK_SIZE
    }

    fn digest_size(&self) -> usize {
        Self::DIGEST_SIZE
    }
}