Skip to main content

uts_core/codec/v1/
digest.rs

1use crate::{
2    alloc::Allocator,
3    codec::{
4        DecodeIn, Decoder, Encode, Encoder,
5        v1::opcode::{DigestOp, DigestOpExt},
6    },
7    error::{DecodeError, EncodeError},
8    utils::Hexed,
9};
10use core::fmt;
11use digest::{Output, typenum::Unsigned};
12
13/// Header describing the digest that anchors a timestamp.
14#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
15#[cfg_attr(
16    feature = "serde",
17    serde_with::serde_as,
18    derive(serde::Serialize, serde::Deserialize)
19)]
20pub struct DigestHeader {
21    pub(crate) kind: DigestOp,
22    #[cfg_attr(feature = "serde", serde_as(as = "serde_with::hex::Hex"))]
23    pub(crate) digest: [u8; 32],
24}
25
26impl fmt::Debug for DigestHeader {
27    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28        f.debug_struct("DigestHeader")
29            .field("kind", &self.kind)
30            .field("digest", &Hexed(self.digest()))
31            .finish()
32    }
33}
34
35impl fmt::Display for DigestHeader {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        write!(f, "{} {}", self.kind, Hexed(self.digest()))
38    }
39}
40
41impl DigestHeader {
42    /// Creates a new digest header from the given digest output.
43    pub fn new<D: DigestOpExt>(digest: Output<D>) -> Self {
44        let mut digest_bytes = [0u8; 32];
45        digest_bytes[..D::OutputSize::USIZE].copy_from_slice(&digest);
46        DigestHeader {
47            kind: D::OPCODE,
48            digest: digest_bytes,
49        }
50    }
51
52    /// Returns the digest opcode recorded in the header.
53    pub fn kind(&self) -> DigestOp {
54        self.kind
55    }
56
57    /// Returns the digest bytes trimmed to the opcode's output size.
58    pub fn digest(&self) -> &[u8] {
59        &self.digest[..self.kind.output_size()]
60    }
61}
62
63impl Encode for DigestHeader {
64    #[tracing::instrument(skip_all, err)]
65    #[inline]
66    fn encode(&self, encoder: &mut impl Encoder) -> Result<(), EncodeError> {
67        encoder.encode(self.kind)?;
68        encoder.write_all(&self.digest[..self.kind.output_size()])?;
69        Ok(())
70    }
71}
72
73impl<A: Allocator> DecodeIn<A> for DigestHeader {
74    #[tracing::instrument(skip_all, ret(level = "trace"), err)]
75    #[inline]
76    fn decode_in(decoder: &mut impl Decoder, _alloc: A) -> Result<DigestHeader, DecodeError> {
77        let kind = decoder.decode()?;
78        let mut digest = [0u8; 32];
79        decoder.read_exact(&mut digest)?;
80
81        Ok(DigestHeader { kind, digest })
82    }
83}