chunky-bits 0.2.0

Chunky Bits is simple, unmanaged, distributed HTTP object store tool.
use std::fmt;

use serde::{
    Deserialize,
    Serialize,
};
use tokio::task::{
    self,
    JoinHandle,
};

use super::Sha256Hash;

pub trait DataHasher: AsRef<[u8]> + Eq + Sized + Send + Sync + 'static {
    fn from_buf(data: &[u8]) -> Self;
    fn from_buf_async<T>(data: T) -> JoinHandle<(Self, T)>
    where
        T: AsRef<[u8]> + Send + Sync + Sized + 'static,
    {
        task::spawn_blocking(move || (<Self as DataHasher>::from_buf(data.as_ref()), data))
    }
}

pub trait DataVerifier: Sized {
    fn verify(&self, data: &[u8]) -> bool;
    fn verify_async<T>(&self, data: T) -> JoinHandle<(bool, T)>
    where
        T: AsRef<[u8]> + Send + Sync + 'static;
}

impl<H> DataVerifier for H
where
    H: DataHasher + Clone,
{
    fn verify(&self, data: &[u8]) -> bool {
        *self == <Self as DataHasher>::from_buf(data)
    }

    fn verify_async<T>(&self, data: T) -> JoinHandle<(bool, T)>
    where
        T: AsRef<[u8]> + Send + Sync + Sized + 'static,
    {
        let inner = self.clone();
        task::spawn_blocking(move || {
            let other = <Self as DataHasher>::from_buf(data.as_ref());
            (inner == other, data)
        })
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AnyHash {
    Sha256(Sha256Hash),
}

impl AnyHash {
    pub fn from_buf(&self, data: &[u8]) -> AnyHash {
        match self {
            AnyHash::Sha256(_) => <Sha256Hash as DataHasher>::from_buf(data).into(),
        }
    }

    pub fn from_buf_async<T>(&self, data: T) -> JoinHandle<(AnyHash, T)>
    where
        T: AsRef<[u8]> + Send + Sync + 'static,
    {
        task::spawn_blocking(match self {
            AnyHash::Sha256(_) => move || {
                (
                    <Sha256Hash as DataHasher>::from_buf(data.as_ref()).into(),
                    data,
                )
            },
        })
    }
}

impl DataVerifier for AnyHash {
    fn verify(&self, data: &[u8]) -> bool {
        match self {
            AnyHash::Sha256(h) => h.verify(data),
        }
    }

    fn verify_async<T>(&self, data: T) -> JoinHandle<(bool, T)>
    where
        T: AsRef<[u8]> + Send + Sync + 'static,
    {
        match self {
            AnyHash::Sha256(h) => h.verify_async(data),
        }
    }
}

impl fmt::Display for AnyHash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use AnyHash::*;
        match self {
            Sha256(h) => write!(f, "sha256-{}", h),
        }
    }
}

impl From<Sha256Hash> for AnyHash {
    fn from(h: Sha256Hash) -> Self {
        AnyHash::Sha256(h)
    }
}

impl AsRef<[u8]> for AnyHash {
    fn as_ref(&self) -> &[u8] {
        use AnyHash::*;
        match self {
            Sha256(h) => h.as_ref(),
        }
    }
}