Skip to main content

quant_codec_core/
digest.rs

1use core::fmt;
2
3#[cfg(feature = "serde")]
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
7#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8pub struct CodecProfileDigest([u8; 32]);
9
10#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12pub struct ArtifactDigest([u8; 32]);
13
14impl CodecProfileDigest {
15    pub fn from_canonical_bytes(bytes: &[u8]) -> Self {
16        Self(*blake3::hash(bytes).as_bytes())
17    }
18
19    pub fn from_parts(parts: &[&[u8]]) -> Self {
20        let mut hasher = blake3::Hasher::new();
21        for part in parts {
22            hasher.update(&(part.len() as u64).to_le_bytes());
23            hasher.update(part);
24        }
25        Self(*hasher.finalize().as_bytes())
26    }
27
28    pub fn as_bytes(&self) -> &[u8; 32] {
29        &self.0
30    }
31
32    pub fn to_hex(self) -> String {
33        hex32(&self.0)
34    }
35}
36
37impl ArtifactDigest {
38    pub fn from_canonical_bytes(bytes: &[u8]) -> Self {
39        Self(*blake3::hash(bytes).as_bytes())
40    }
41
42    pub fn from_parts(parts: &[&[u8]]) -> Self {
43        let mut hasher = blake3::Hasher::new();
44        for part in parts {
45            hasher.update(&(part.len() as u64).to_le_bytes());
46            hasher.update(part);
47        }
48        Self(*hasher.finalize().as_bytes())
49    }
50
51    pub fn as_bytes(&self) -> &[u8; 32] {
52        &self.0
53    }
54
55    pub fn to_hex(self) -> String {
56        hex32(&self.0)
57    }
58}
59
60impl fmt::Debug for CodecProfileDigest {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        f.debug_tuple("CodecProfileDigest")
63            .field(&self.to_hex())
64            .finish()
65    }
66}
67
68impl fmt::Display for CodecProfileDigest {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        f.write_str(&self.to_hex())
71    }
72}
73
74impl fmt::Debug for ArtifactDigest {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        f.debug_tuple("ArtifactDigest")
77            .field(&self.to_hex())
78            .finish()
79    }
80}
81
82impl fmt::Display for ArtifactDigest {
83    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84        f.write_str(&self.to_hex())
85    }
86}
87
88fn hex32(bytes: &[u8; 32]) -> String {
89    const HEX: &[u8; 16] = b"0123456789abcdef";
90    let mut out = [0u8; 64];
91    for (idx, byte) in bytes.iter().enumerate() {
92        out[idx * 2] = HEX[(byte >> 4) as usize];
93        out[idx * 2 + 1] = HEX[(byte & 0x0f) as usize];
94    }
95    String::from_utf8(out.to_vec()).expect("hex table is valid utf8")
96}