mod sha;

#[derive(Debug, Clone)]
pub struct Hash {
    hash: [u8; 32],
}

impl<B> From<B> for Hash
where
    B: AsRef<[u8]>,
{
    fn from(bytes: B) -> Self {
        Hash {
            hash: sha::sha256(bytes.as_ref()),
        }
    }
}

impl Hash {
    pub fn as_bytes(&self) -> [u8; 32] {
        self.hash
    }

    pub fn as_bytes_capped<const N: usize>(&self) -> [u8; N] {
        let mut hash = [0u8; N];
        hash.copy_from_slice(&self.hash[..N]);
        hash
    }

    pub fn new<B>(bytes: B) -> Self
    where
        B: AsRef<[u8]>,
    {
        Self::from(bytes)
    }
}

impl ToString for Hash {
    fn to_string(&self) -> String {
        self.hash.iter().map(|b| format!("{:02x}", b)).collect()
    }
}

pub trait Hashable {
    fn hash(&self) -> Hash;
}

impl Hashable for String {
    fn hash(&self) -> Hash {
        Hash::from(self.as_bytes())
    }
}

impl Hashable for &str {
    fn hash(&self) -> Hash {
        Hash::from(self.as_bytes())
    }
}
