radicle-heartwood-lfs/radicle/src/hash.rs

70 lines
1.6 KiB
Rust

use std::{convert::TryInto, fmt};
use serde::{Deserialize, Serialize};
use sha2::{
digest::{generic_array::GenericArray, OutputSizeUser},
Digest as _, Sha256,
};
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum DecodeError {
#[error("invalid digest length {0}")]
InvalidLength(usize),
}
/// A SHA-256 hash.
#[derive(Serialize, Deserialize, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Digest([u8; 32]);
impl Digest {
pub fn new(bytes: impl AsRef<[u8]>) -> Self {
Self::from(Sha256::digest(bytes))
}
}
impl AsRef<[u8; 32]> for Digest {
fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}
impl fmt::Debug for Digest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Hash({})", self)
}
}
impl fmt::Display for Digest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in &self.0 {
write!(f, "{:02x}", byte)?;
}
Ok(())
}
}
impl From<[u8; 32]> for Digest {
fn from(bytes: [u8; 32]) -> Self {
Self(bytes)
}
}
impl TryFrom<&[u8]> for Digest {
type Error = DecodeError;
fn try_from(bytes: &[u8]) -> Result<Self, DecodeError> {
let bytes: [u8; 32] = bytes
.try_into()
.map_err(|_| DecodeError::InvalidLength(bytes.len()))?;
Ok(bytes.into())
}
}
impl From<GenericArray<u8, <Sha256 as OutputSizeUser>::OutputSize>> for Digest {
fn from(array: GenericArray<u8, <Sha256 as OutputSizeUser>::OutputSize>) -> Self {
Self(array.into())
}
}