Skip to main content

uts_core/codec/v1/
detached_timestamp.rs

1use crate::{
2    alloc::{Allocator, Global},
3    codec::{
4        Decode, DecodeIn, Encode, Encoder, Proof, Version,
5        v1::{DigestHeader, FinalizationError, Timestamp},
6    },
7};
8use core::{fmt, fmt::Formatter};
9use std::ops::{Deref, DerefMut};
10
11/// A file containing a timestamp for another file
12/// Contains a timestamp, along with a header and the digest of the file.
13///
14/// This is not equivalent to the python DetachedTimestamp structure,
15/// which don't encode/decode the magic and version.
16/// The Python version is equivalent to `VersionedProof<DetachedTimestamp>`.
17#[derive(Clone, PartialEq, Eq, Debug)]
18pub struct DetachedTimestamp<A: Allocator = Global> {
19    header: DigestHeader,
20    timestamp: Timestamp<A>,
21}
22
23impl<A: Allocator + Clone> Proof<A> for DetachedTimestamp<A> {
24    const VERSION: Version = 1;
25}
26
27impl<A: Allocator + Clone> DecodeIn<A> for DetachedTimestamp<A> {
28    fn decode_in(
29        decoder: &mut impl crate::codec::Decoder,
30        alloc: A,
31    ) -> Result<Self, crate::error::DecodeError> {
32        let header = DigestHeader::decode(decoder)?;
33        let timestamp = Timestamp::decode_in(decoder, alloc)?;
34        let detached = DetachedTimestamp { header, timestamp };
35        detached.finalize();
36        Ok(detached)
37    }
38}
39
40impl<A: Allocator> Encode for DetachedTimestamp<A> {
41    fn encode(&self, encoder: &mut impl Encoder) -> Result<(), crate::error::EncodeError> {
42        self.header.encode(encoder)?;
43        self.timestamp.encode(encoder)?;
44        Ok(())
45    }
46}
47
48impl<A: Allocator + Clone> fmt::Display for DetachedTimestamp<A> {
49    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
50        writeln!(f, "digest of {}", self.header)?;
51
52        self.timestamp.fmt(Some(self.header.digest()), f)
53    }
54}
55
56impl<A: Allocator> DetachedTimestamp<A> {
57    /// Returns the digest header.
58    pub fn header(&self) -> &DigestHeader {
59        &self.header
60    }
61
62    /// Returns the timestamp.
63    pub fn timestamp(&self) -> &Timestamp<A> {
64        &self.timestamp
65    }
66
67    /// Returns the allocator used by this detached timestamp.
68    #[inline]
69    pub fn allocator(&self) -> &A {
70        self.timestamp.allocator()
71    }
72
73    /// Consumes the detached timestamp and returns its parts.
74    pub fn into_parts(self) -> (DigestHeader, Timestamp<A>) {
75        (self.header, self.timestamp)
76    }
77}
78
79impl<A: Allocator + Clone> DetachedTimestamp<A> {
80    /// Creates a new detached timestamp from the given header and timestamp.
81    ///
82    /// # Panics
83    ///
84    /// Panics if the timestamp cannot be finalized with the given header's digest.
85    pub fn from_parts(header: DigestHeader, timestamp: Timestamp<A>) -> Self {
86        Self::try_from_parts(header, timestamp)
87            .expect("conflicting inputs when finalizing detached timestamp")
88    }
89
90    /// Creates a new detached timestamp from the given header and timestamp.
91    ///
92    /// Returns an error if the timestamp cannot be finalized with the given header's digest.
93    pub fn try_from_parts(
94        header: DigestHeader,
95        timestamp: Timestamp<A>,
96    ) -> Result<Self, FinalizationError> {
97        timestamp.try_finalize(header.digest())?;
98        Ok(DetachedTimestamp { header, timestamp })
99    }
100
101    /// Finalize the detached timestamp's timestamp with the header's digest.
102    ///
103    /// # Panics
104    ///
105    /// Panics if the timestamp cannot be finalized.
106    pub fn finalize(&self) {
107        self.try_finalize()
108            .expect("conflicting inputs when finalizing detached timestamp");
109    }
110
111    /// Tries to finalize the detached timestamp's timestamp with the header's digest.
112    ///
113    /// Returns an error if the timestamp cannot be finalized.
114    pub fn try_finalize(&self) -> Result<(), FinalizationError> {
115        self.timestamp.try_finalize(self.header.digest())
116    }
117}
118
119impl<A: Allocator> Deref for DetachedTimestamp<A> {
120    type Target = Timestamp<A>;
121
122    fn deref(&self) -> &Self::Target {
123        &self.timestamp
124    }
125}
126
127impl<A: Allocator> DerefMut for DetachedTimestamp<A> {
128    fn deref_mut(&mut self) -> &mut Self::Target {
129        &mut self.timestamp
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136    use crate::{
137        codec::{Decode, Encoder, proof::VersionedProof},
138        fixtures,
139    };
140
141    #[test]
142    fn round_trip() {
143        let mut encoded_small = vec![];
144        let mut encoded_large = vec![];
145
146        let ots =
147            VersionedProof::<DetachedTimestamp>::decode(&mut &*fixtures::SMALL_DETACHED_TIMESTAMP)
148                .unwrap();
149        println!("{:#?}", ots);
150        println!("{}", ots);
151        assert!(encoded_small.encode(&ots).is_ok());
152        assert_eq!(encoded_small, fixtures::SMALL_DETACHED_TIMESTAMP);
153
154        let ots =
155            VersionedProof::<DetachedTimestamp>::decode(&mut &*fixtures::LARGE_DETACHED_TIMESTAMP)
156                .unwrap();
157        assert!(encoded_large.encode(&ots).is_ok());
158        assert_eq!(encoded_large, fixtures::LARGE_DETACHED_TIMESTAMP);
159    }
160}