use serde::Serialize;
use crate::error::HostError;
pub type Digest = [u8; 32];
pub(crate) fn canonical_digest<T: Serialize>(value: &T) -> Result<Digest, HostError> {
let bytes =
batpak::canonical::to_bytes(value).map_err(|error| HostError::CanonicalEncoding {
detail: error.to_string(),
})?;
Ok(batpak::event::hash::compute_hash(&bytes))
}
fn hex(digest: &Digest) -> String {
let mut out = String::with_capacity(64);
for byte in digest {
out.push(char::from_digit(u32::from(byte >> 4), 16).unwrap_or('0'));
out.push(char::from_digit(u32::from(byte & 0x0f), 16).unwrap_or('0'));
}
out
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModuleDigest(pub Digest);
impl ModuleDigest {
#[must_use]
pub const fn bytes(&self) -> &Digest {
&self.0
}
#[must_use]
pub fn to_hex(&self) -> String {
hex(&self.0)
}
}
impl std::fmt::Display for ModuleDigest {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_hex())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct HostFingerprint(pub Digest);
impl HostFingerprint {
#[must_use]
pub const fn bytes(&self) -> &Digest {
&self.0
}
#[must_use]
pub fn to_hex(&self) -> String {
hex(&self.0)
}
}
impl std::fmt::Display for HostFingerprint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_hex())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InterfaceFingerprint(pub Digest);
impl InterfaceFingerprint {
#[must_use]
pub const fn bytes(&self) -> &Digest {
&self.0
}
#[must_use]
pub fn to_hex(&self) -> String {
hex(&self.0)
}
}
impl std::fmt::Display for InterfaceFingerprint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_hex())
}
}