use std::fmt;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use crate::errors::NameError;
pub const FINGERPRINT_VERSION: u32 = 1;
const DIGEST_LEN: usize = 16;
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(try_from = "String", into = "String")]
pub struct VerdictFingerprint(String);
impl VerdictFingerprint {
#[must_use]
pub fn from_digest(digest: [u8; DIGEST_LEN]) -> Self {
const HEX: &[u8; 16] = b"0123456789abcdef";
let mut hex = String::with_capacity(DIGEST_LEN * 2);
for byte in digest {
hex.push(HEX[usize::from(byte >> 4)] as char);
hex.push(HEX[usize::from(byte & 0x0f)] as char);
}
Self(hex)
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn into_inner(self) -> String {
self.0
}
}
impl TryFrom<String> for VerdictFingerprint {
type Error = NameError;
fn try_from(value: String) -> Result<Self, NameError> {
let valid = value.len() == DIGEST_LEN * 2
&& value
.chars()
.all(|c| c.is_ascii_hexdigit() && !c.is_ascii_uppercase());
if !valid {
return Err(NameError::InvalidVerdictFingerprint { value });
}
Ok(Self(value))
}
}
impl From<VerdictFingerprint> for String {
fn from(f: VerdictFingerprint) -> Self {
f.0
}
}
impl AsRef<str> for VerdictFingerprint {
fn as_ref(&self) -> &str {
&self.0
}
}
impl fmt::Display for VerdictFingerprint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl FromStr for VerdictFingerprint {
type Err = NameError;
fn from_str(s: &str) -> Result<Self, NameError> {
Self::try_from(s.to_owned())
}
}