uts_core/codec/v1/
detached_timestamp.rs1use 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#[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 pub fn header(&self) -> &DigestHeader {
59 &self.header
60 }
61
62 pub fn timestamp(&self) -> &Timestamp<A> {
64 &self.timestamp
65 }
66
67 #[inline]
69 pub fn allocator(&self) -> &A {
70 self.timestamp.allocator()
71 }
72
73 pub fn into_parts(self) -> (DigestHeader, Timestamp<A>) {
75 (self.header, self.timestamp)
76 }
77}
78
79impl<A: Allocator + Clone> DetachedTimestamp<A> {
80 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 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 pub fn finalize(&self) {
107 self.try_finalize()
108 .expect("conflicting inputs when finalizing detached timestamp");
109 }
110
111 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}