Skip to main content

uts_core/
codec.rs

1use crate::{
2    alloc::{Allocator, Global},
3    error::{DecodeError, EncodeError},
4};
5use auto_impl::auto_impl;
6use core::ops::RangeBounds;
7
8mod proof;
9pub use proof::{Proof, Version, VersionedProof};
10
11mod imp;
12pub use imp::{Reader, Writer};
13
14/// Types and helpers for the version 1 serialization format.
15pub mod v1;
16
17/// Magic bytes that every proof must start with.
18pub const MAGIC: &[u8; 31] = b"\x00OpenTimestamps\x00\x00Proof\x00\xbf\x89\xe2\xe8\x84\xe8\x92\x94";
19
20/// Helper trait for writing OpenTimestamps primitives to a byte stream.
21pub trait Encoder: Sized {
22    /// Encodes a single byte to the writer.
23    fn encode_byte(&mut self, byte: u8) -> Result<(), EncodeError>;
24
25    /// Encodes a byte slice prefixed with its length.
26    fn encode_bytes(&mut self, bytes: impl AsRef<[u8]>) -> Result<(), EncodeError> {
27        let bytes = bytes.as_ref();
28        self.encode(bytes.len())?;
29        self.write_all(bytes)?;
30        Ok(())
31    }
32
33    /// Writes the OpenTimestamps magic sequence to the stream.
34    fn encode_magic(&mut self) -> Result<(), EncodeError> {
35        self.write_all(&MAGIC[..])
36    }
37
38    /// Encodes a value implementing the [`Encode`] trait.
39    fn encode(&mut self, value: impl Encode) -> Result<(), EncodeError> {
40        value.encode(self)
41    }
42
43    // --- no_std feature compatibility ---
44    fn write_all(&mut self, buf: impl AsRef<[u8]>) -> Result<(), EncodeError>;
45}
46
47/// Helper trait for reading OpenTimestamps primitives from a byte stream.
48pub trait Decoder: Sized {
49    /// Decodes a single byte from the reader.
50    fn decode_byte(&mut self) -> Result<u8, DecodeError>;
51
52    /// Decodes a value and ensures it falls within the supplied range.
53    fn decode_ranged<T: Decode + PartialOrd>(
54        &mut self,
55        range: impl RangeBounds<T>,
56    ) -> Result<T, DecodeError> {
57        let val: T = self.decode()?;
58        if range.contains(&val) {
59            Ok(val)
60        } else {
61            Err(DecodeError::OutOfRange)
62        }
63    }
64
65    /// Verifies that the next bytes in the stream match the magic sequence.
66    fn assert_magic(&mut self) -> Result<(), DecodeError> {
67        let mut buf = [0u8; MAGIC.len()];
68        self.read_exact(&mut buf)?;
69        if buf == *MAGIC {
70            Ok(())
71        } else {
72            Err(DecodeError::BadMagic)
73        }
74    }
75
76    /// Decodes a value implementing the [`Decode`] trait.
77    fn decode<T: Decode>(&mut self) -> Result<T, DecodeError> {
78        T::decode(self)
79    }
80
81    /// Decodes a trailing optional value implementing the [`Decode`] trait.
82    ///
83    /// See [`Decode::decode_trailing`] for details and caveats.
84    fn decode_trailing<T: Decode>(&mut self) -> Result<Option<T>, DecodeError> {
85        T::decode_trailing(self)
86    }
87
88    /// Decodes a value implementing the [`Decode`] trait.
89    fn decode_in<T: DecodeIn<A>, A: Allocator>(&mut self, alloc: A) -> Result<T, DecodeError> {
90        T::decode_in(self, alloc)
91    }
92
93    // --- no_std feature compatibility ---
94    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), DecodeError>;
95}
96
97/// Serializes a value into an OpenTimestamps-compatible byte stream.
98#[auto_impl(&, &mut, Box, Rc, Arc)]
99pub trait Encode {
100    fn encode(&self, writer: &mut impl Encoder) -> Result<(), EncodeError>;
101}
102
103/// Deserializes a value from an OpenTimestamps-compatible byte stream.
104pub trait Decode: Sized {
105    fn decode(decoder: &mut impl Decoder) -> Result<Self, DecodeError>;
106
107    /// Decodes a trailing optional value implementing the [`Decode`] trait.
108    ///
109    /// This treats any `UnexpectedEof` error as an indication that the value is absent, returning `Ok(None)`.
110    ///
111    /// If the implementor returns `UnexpectedEof` for any reason other than the absence of the value,
112    /// it should also override this method to avoid masking the error as `Ok(None)`.
113    fn decode_trailing(decoder: &mut impl Decoder) -> Result<Option<Self>, DecodeError> {
114        match Self::decode(decoder) {
115            Ok(value) => Ok(Some(value)),
116            Err(DecodeError::UnexpectedEof) => Ok(None),
117            Err(e) => Err(e),
118        }
119    }
120}
121
122/// Deserializes a value from an OpenTimestamps-compatible byte stream.
123pub trait DecodeIn<A: Allocator>: Sized {
124    /// See [`Decode::decode`] for details.
125    fn decode_in(decoder: &mut impl Decoder, alloc: A) -> Result<Self, DecodeError>;
126
127    /// See [`Decode::decode_trailing`] for details and caveats.
128    fn decode_trailing(decoder: &mut impl Decoder, alloc: A) -> Result<Option<Self>, DecodeError> {
129        match Self::decode_in(decoder, alloc) {
130            Ok(value) => Ok(Some(value)),
131            Err(DecodeError::UnexpectedEof) => Ok(None),
132            Err(e) => Err(e),
133        }
134    }
135}
136
137impl<T: DecodeIn<Global>> Decode for T {
138    fn decode(decoder: &mut impl Decoder) -> Result<Self, DecodeError> {
139        T::decode_in(decoder, Global)
140    }
141
142    fn decode_trailing(decoder: &mut impl Decoder) -> Result<Option<Self>, DecodeError> {
143        match Self::decode_in(decoder, Global) {
144            Ok(value) => Ok(Some(value)),
145            Err(DecodeError::UnexpectedEof) => Ok(None),
146            Err(e) => Err(e),
147        }
148    }
149}