uqa_analysis/descriptor/
hash.rs1use std::{fmt, str::FromStr};
10
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12use sha2::{Digest, Sha256};
13
14use crate::{AnalysisError, AnalysisResult};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct AnalyzerFingerprint([u8; 32]);
18
19impl AnalyzerFingerprint {
20 pub const fn as_bytes(&self) -> &[u8; 32] {
22 &self.0
23 }
24
25 pub const fn from_bytes(bytes: [u8; 32]) -> Self {
27 Self(bytes)
28 }
29
30 pub(super) fn digest(bytes: &[u8]) -> Self {
31 let mut hash = Sha256::new();
32 hash.update(b"UQA analyzer descriptor\0");
33 hash.update(bytes);
34 Self(hash.finalize().into())
35 }
36}
37
38impl fmt::Display for AnalyzerFingerprint {
39 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
40 for byte in self.0 {
41 write!(formatter, "{byte:02x}")?;
42 }
43 Ok(())
44 }
45}
46
47impl FromStr for AnalyzerFingerprint {
48 type Err = AnalysisError;
49
50 fn from_str(text: &str) -> AnalysisResult<Self> {
51 if text.len() != 64 || !text.bytes().all(|byte| byte.is_ascii_hexdigit()) {
52 return Err(super::invalid("fingerprint requires 64 hexadecimal digits"));
53 }
54 let mut bytes = [0; 32];
55 for (index, byte) in bytes.iter_mut().enumerate() {
56 *byte = u8::from_str_radix(&text[index * 2..index * 2 + 2], 16)
57 .map_err(|_| super::invalid("invalid fingerprint byte"))?;
58 }
59 Ok(Self(bytes))
60 }
61}
62
63impl Serialize for AnalyzerFingerprint {
64 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
65 serializer.collect_str(self)
66 }
67}
68
69impl<'de> Deserialize<'de> for AnalyzerFingerprint {
70 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
71 String::deserialize(deserializer)?
72 .parse()
73 .map_err(serde::de::Error::custom)
74 }
75}