use core::fmt;
use heapless::String;
use sha2::{Sha256, digest::Output};
const SHA256_LEN: usize = 256 / 0xF_u8.count_ones() as usize;
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Sha256String(String<SHA256_LEN>);
impl Sha256String {
#[must_use]
pub fn from_digest(digest: &Output<Sha256>) -> Self {
let mut encode_buf = [0; SHA256_LEN];
Self(
base16ct::upper::encode_str(digest, &mut encode_buf)
.unwrap_or_else(|_| unreachable!("SHA256 digests should always be 32 bytes long"))
.parse::<String<SHA256_LEN>>()
.unwrap_or_else(|_| {
unreachable!("Sha256 hashes should always be {SHA256_LEN} bytes long")
}),
)
}
#[cfg(feature = "std")]
pub fn hash_from_reader<R: std::io::Read>(mut reader: R) -> std::io::Result<Self> {
use sha2::{Digest, Sha256};
let mut hasher = Sha256::new();
let mut buffer = [0; 1 << 12];
loop {
let count = reader.read(&mut buffer)?;
if count == 0 {
break;
}
hasher.update(&buffer[..count]);
}
Ok(Self::from_digest(&hasher.finalize()))
}
#[must_use]
#[inline]
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl Default for Sha256String {
fn default() -> Self {
Self(core::iter::repeat_n('0', SHA256_LEN).collect::<_>())
}
}
impl fmt::Display for Sha256String {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}