use std::str::FromStr;
use bherror::Error;
use serde::{Deserialize, Serialize};
use crate::DecodingError;
pub(crate) const SHA_256_ALG_NAME: &str = "sha-256";
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum HashingAlgorithm {
#[serde(rename = "sha-256")]
#[default]
Sha256,
}
impl HashingAlgorithm {
pub fn as_str(&self) -> &'static str {
match self {
HashingAlgorithm::Sha256 => SHA_256_ALG_NAME,
}
}
}
impl FromStr for HashingAlgorithm {
type Err = bherror::Error<DecodingError>;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
SHA_256_ALG_NAME => Ok(Self::Sha256),
_ => Err(Error::root(DecodingError::InvalidHashAlgorithmName(
value.to_owned(),
))),
}
}
}
impl std::fmt::Display for HashingAlgorithm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
pub trait Hasher: Send + Sync {
fn algorithm(&self) -> HashingAlgorithm;
fn digest(&self, input: &[u8]) -> Vec<u8>;
}
impl<H: Hasher> Hasher for &H {
fn algorithm(&self) -> HashingAlgorithm {
(*self).algorithm()
}
fn digest(&self, input: &[u8]) -> Vec<u8> {
(*self).digest(input)
}
}
impl<H: Hasher> Hasher for Box<H> {
fn algorithm(&self) -> HashingAlgorithm {
self.as_ref().algorithm()
}
fn digest(&self, input: &[u8]) -> Vec<u8> {
self.as_ref().digest(input)
}
}
impl Hasher for &dyn Hasher {
fn algorithm(&self) -> HashingAlgorithm {
(*self).algorithm()
}
fn digest(&self, input: &[u8]) -> Vec<u8> {
(*self).digest(input)
}
}
impl Hasher for Box<dyn Hasher> {
fn algorithm(&self) -> HashingAlgorithm {
self.as_ref().algorithm()
}
fn digest(&self, input: &[u8]) -> Vec<u8> {
self.as_ref().digest(input)
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
#[test]
fn hashing_algorithm_sha256_serializes_correctly() {
let alg = HashingAlgorithm::Sha256;
let expected = format!("\"{}\"", SHA_256_ALG_NAME);
let serialized = serde_json::to_string(&alg).unwrap();
assert_eq!(serialized, expected);
let deserialized: HashingAlgorithm = serde_json::from_str(&expected).unwrap();
assert_eq!(deserialized, alg);
}
}