use crate::{algorithm::HashAlgorithm, error::Error};
#[cfg(feature = "serde")]
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
use std::{
fmt::{self, Display},
str::FromStr,
};
use subtle_encoding::{Encoding, Hex};
pub const SHA256_HASH_SIZE: usize = 32;
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum Hash {
Sha256([u8; SHA256_HASH_SIZE]),
}
impl Hash {
#[allow(clippy::new_ret_no_self)]
pub fn new(alg: HashAlgorithm, bytes: &[u8]) -> Result<Hash, Error> {
match alg {
HashAlgorithm::Sha256 => {
if bytes.len() == SHA256_HASH_SIZE {
let mut h = [0u8; SHA256_HASH_SIZE];
h.copy_from_slice(bytes);
Ok(Hash::Sha256(h))
} else {
Err(Error::Parse)
}
}
}
}
pub fn from_hex_upper(alg: HashAlgorithm, s: &str) -> Result<Hash, Error> {
match alg {
HashAlgorithm::Sha256 => {
let mut h = [0u8; SHA256_HASH_SIZE];
Hex::upper_case().decode_to_slice(s.as_bytes(), &mut h)?;
Ok(Hash::Sha256(h))
}
}
}
pub fn as_slice(&self) -> &[u8] {
match self {
Hash::Sha256(ref h) => h.as_ref(),
}
}
}
impl AsRef<[u8]> for Hash {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl Display for Hash {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let hex = match self {
Hash::Sha256(ref h) => Hex::upper_case().encode_to_string(h).unwrap(),
};
write!(f, "{}", hex)
}
}
impl FromStr for Hash {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
Self::from_hex_upper(HashAlgorithm::Sha256, s)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Hash {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
Ok(Self::from_str(&String::deserialize(deserializer)?)
.map_err(|e| D::Error::custom(format!("{}", e)))?)
}
}
#[cfg(feature = "serde")]
impl Serialize for Hash {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
self.to_string().serialize(serializer)
}
}