quant_codec_core/
digest.rs1use 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}