use std::fmt::{self, Display, Formatter};
use rkyv::{Archive, CheckBytes, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
#[cfg(feature = "enable-serde")]
use serde::{Deserialize, Serialize};
use sha2::Digest;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum HashAlgorithm {
Sha256,
XXHash,
}
#[derive(
Debug,
Copy,
Clone,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
RkyvSerialize,
RkyvDeserialize,
Archive,
)]
#[archive_attr(derive(CheckBytes, Debug))]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub enum ModuleHash {
XXHash([u8; 8]),
Sha256([u8; 32]),
}
impl ModuleHash {
pub fn xxhash_from_bytes(key: [u8; 8]) -> Self {
Self::XXHash(key)
}
pub fn sha256_from_bytes(key: [u8; 32]) -> Self {
Self::Sha256(key)
}
pub fn xxhash_parse_hex(hex_str: &str) -> Result<Self, hex::FromHexError> {
let mut hash = [0_u8; 8];
hex::decode_to_slice(hex_str, &mut hash)?;
Ok(Self::xxhash_from_bytes(hash))
}
pub fn sha256_parse_hex(hex_str: &str) -> Result<Self, hex::FromHexError> {
let mut hash = [0_u8; 32];
hex::decode_to_slice(hex_str, &mut hash)?;
Ok(Self::sha256_from_bytes(hash))
}
pub fn xxhash(wasm: impl AsRef<[u8]>) -> Self {
let wasm = wasm.as_ref();
let hash = xxhash_rust::xxh64::xxh64(wasm, 0);
Self::XXHash(hash.to_ne_bytes())
}
pub fn sha256(wasm: impl AsRef<[u8]>) -> Self {
let wasm = wasm.as_ref();
let hash: [u8; 32] = sha2::Sha256::digest(wasm).into();
Self::Sha256(hash)
}
pub fn as_bytes(&self) -> &[u8] {
match self {
Self::XXHash(bytes) => bytes.as_slice(),
Self::Sha256(bytes) => bytes.as_slice(),
}
}
}
impl From<webc::metadata::AtomSignature> for ModuleHash {
fn from(value: webc::metadata::AtomSignature) -> Self {
match value {
webc::metadata::AtomSignature::Sha256(bytes) => Self::Sha256(bytes),
}
}
}
impl Display for ModuleHash {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fn format<const N: usize>(f: &mut Formatter<'_>, bytes: &[u8; N]) -> fmt::Result {
for byte in bytes {
write!(f, "{byte:02X}")?;
}
Ok(())
}
match self {
Self::XXHash(bytes) => format(f, bytes)?,
Self::Sha256(bytes) => format(f, bytes)?,
}
Ok(())
}
}