tidecoin_consensus_encoding/encode/mod.rs
1// SPDX-License-Identifier: CC0-1.0
2
3//! Consensus Encoding Traits
4
5#[cfg(feature = "alloc")]
6use alloc::vec::Vec;
7
8pub mod encoders;
9
10/// A Tidecoin object which can be consensus-encoded.
11///
12/// To encode something, use the [`Self::encoder`] method to obtain a [`Self::Encoder`], which will
13/// behave like an iterator yielding byte slices.
14///
15/// # Examples
16///
17/// ```
18/// # #[cfg(feature = "alloc")] {
19/// use tidecoin_consensus_encoding::{encoder_newtype, encode_to_vec, Encodable, ArrayEncoder};
20///
21/// struct Foo([u8; 4]);
22///
23/// encoder_newtype! {
24/// pub struct FooEncoder<'e>(ArrayEncoder<4>);
25/// }
26///
27/// impl Encodable for Foo {
28/// type Encoder<'e> = FooEncoder<'e> where Self: 'e;
29///
30/// fn encoder(&self) -> Self::Encoder<'_> {
31/// FooEncoder::new(ArrayEncoder::without_length_prefix(self.0))
32/// }
33/// }
34///
35/// let foo = Foo([0xde, 0xad, 0xbe, 0xef]);
36/// assert_eq!(encode_to_vec(&foo), vec![0xde, 0xad, 0xbe, 0xef]);
37/// # }
38/// ```
39pub trait Encodable {
40 /// The encoder associated with this type. Conceptually, the encoder is like
41 /// an iterator which yields byte slices.
42 type Encoder<'e>: Encoder
43 where
44 Self: 'e;
45
46 /// Constructs a "default encoder" for the type.
47 fn encoder(&self) -> Self::Encoder<'_>;
48}
49
50/// An encoder for a consensus-encodable object.
51pub trait Encoder {
52 /// Yields the current encoded byteslice.
53 ///
54 /// Will always return the same value until [`Self::advance`] is called.
55 /// May return an empty list.
56 fn current_chunk(&self) -> &[u8];
57
58 /// Moves the encoder to its next state.
59 ///
60 /// Does not need to be called when the encoder is first created. (In fact, if it
61 /// is called, this will discard the first chunk of encoded data.)
62 ///
63 /// # Returns
64 ///
65 /// - `true` if the encoder has advanced to a new state and [`Self::current_chunk`] will return new data.
66 /// - `false` if the encoder is exhausted and has no more states.
67 fn advance(&mut self) -> bool;
68}
69
70/// Implements a newtype around an encoder.
71///
72/// The new type will implement the [`Encoder`] trait by forwarding to the wrapped encoder. If your
73/// type has a known size consider using [`crate::encoder_newtype_exact`] instead.
74///
75/// # Examples
76/// ```
77/// use tidecoin_consensus_encoding::{encoder_newtype, BytesEncoder};
78///
79/// encoder_newtype! {
80/// /// The encoder for the [`Foo`] type.
81/// pub struct FooEncoder<'e>(BytesEncoder<'e>);
82/// }
83/// ```
84///
85/// For a full example see `./examples/encoder.rs`.
86#[macro_export]
87macro_rules! encoder_newtype {
88 (
89 $(#[$($struct_attr:tt)*])*
90 $vis:vis struct $name:ident<$lt:lifetime>($encoder:ty);
91 ) => {
92 $(#[$($struct_attr)*])*
93 $vis struct $name<$lt>($encoder, core::marker::PhantomData<&$lt $encoder>);
94
95 #[allow(clippy::type_complexity)]
96 impl<$lt> $name<$lt> {
97 /// Constructs a new instance of the newtype encoder.
98 pub(crate) const fn new(encoder: $encoder) -> $name<$lt> {
99 $name(encoder, core::marker::PhantomData)
100 }
101 }
102
103 impl<$lt> $crate::Encoder for $name<$lt> {
104 #[inline]
105 fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
106
107 #[inline]
108 fn advance(&mut self) -> bool { self.0.advance() }
109 }
110 }
111}
112
113/// Implements a newtype around an exact-size encoder.
114///
115/// The new type will implement both the [`Encoder`] and [`ExactSizeEncoder`] traits
116/// by forwarding to the wrapped encoder.
117///
118/// # Examples
119/// ```
120/// use tidecoin_consensus_encoding::{encoder_newtype_exact, ArrayEncoder};
121///
122/// encoder_newtype_exact! {
123/// /// The encoder for the [`Bar`] type.
124/// pub struct BarEncoder<'e>(ArrayEncoder<32>);
125/// }
126/// ```
127///
128/// For a full example see `./examples/encoder.rs`.
129#[macro_export]
130macro_rules! encoder_newtype_exact {
131 (
132 $(#[$($struct_attr:tt)*])*
133 $vis:vis struct $name:ident<$lt:lifetime>($encoder:ty);
134 ) => {
135 $crate::encoder_newtype! {
136 $(#[$($struct_attr)*])*
137 $vis struct $name<$lt>($encoder);
138 }
139
140 impl<$lt> $crate::ExactSizeEncoder for $name<$lt> {
141 #[inline]
142 fn len(&self) -> usize { self.0.len() }
143 }
144 }
145}
146
147/// Yields bytes from any [`Encodable`] instance.
148#[derive(Debug)]
149pub struct EncodableByteIter<'e, T: Encodable + ?Sized + 'e> {
150 enc: T::Encoder<'e>,
151 position: usize,
152}
153
154impl<'e, T: Encodable + ?Sized + 'e> EncodableByteIter<'e, T> {
155 /// Constructs a new byte iterator around a provided encodable.
156 pub fn new(encodable: &'e T) -> Self {
157 Self { enc: encodable.encoder(), position: 0 }
158 }
159}
160
161// Manual impl rather than #[derive(Clone)] because derive would constrain `where T: Clone`,
162// but `T` itself is never cloned, only the associated type `T::Encoder<'e>`.
163impl<'e, T: Encodable + ?Sized + 'e> Clone for EncodableByteIter<'e, T>
164where
165 T::Encoder<'e>: Clone,
166{
167 fn clone(&self) -> Self {
168 Self { enc: self.enc.clone(), position: self.position }
169 }
170}
171
172impl<'e, T: Encodable + ?Sized + 'e> Iterator for EncodableByteIter<'e, T> {
173 type Item = u8;
174
175 fn next(&mut self) -> Option<Self::Item> {
176 loop {
177 if let Some(b) = self.enc.current_chunk().get(self.position) {
178 self.position += 1;
179 return Some(*b);
180 } else if !self.enc.advance() {
181 return None;
182 }
183 self.position = 0;
184 }
185 }
186}
187
188impl<'e, T> ExactSizeIterator for EncodableByteIter<'e, T>
189where
190 T: Encodable + ?Sized + 'e,
191 T::Encoder<'e>: ExactSizeEncoder,
192{
193 fn len(&self) -> usize {
194 self.enc.len() - self.position
195 }
196}
197
198/// An encoder with a known size.
199pub trait ExactSizeEncoder: Encoder {
200 /// The number of bytes remaining that the encoder will yield.
201 fn len(&self) -> usize;
202
203 /// Returns whether the encoder would yield an empty response.
204 fn is_empty(&self) -> bool {
205 self.len() == 0
206 }
207}
208
209/// Encodes an object into a vector.
210#[cfg(feature = "alloc")]
211pub fn encode_to_vec<T>(object: &T) -> Vec<u8>
212where
213 T: Encodable + ?Sized,
214{
215 let mut encoder = object.encoder();
216 flush_to_vec(&mut encoder)
217}
218
219/// Flushes the output of an [`Encoder`] into a vector.
220#[cfg(feature = "alloc")]
221pub fn flush_to_vec<T>(encoder: &mut T) -> Vec<u8>
222where
223 T: Encoder + ?Sized,
224{
225 let mut vec = Vec::new();
226 loop {
227 vec.extend_from_slice(encoder.current_chunk());
228 if !encoder.advance() {
229 break;
230 }
231 }
232 vec
233}
234
235/// Encodes an object to a standard I/O writer.
236///
237/// # Performance
238///
239/// This method writes data in potentially small chunks based on the encoder's internal chunking
240/// strategy. For optimal performance with unbuffered writers (like [`std::fs::File`] or
241/// [`std::net::TcpStream`]), consider wrapping your writer with [`std::io::BufWriter`].
242///
243/// # Errors
244///
245/// Returns any I/O error encountered while writing to the writer.
246#[cfg(feature = "std")]
247pub fn encode_to_writer<T, W>(object: &T, writer: W) -> Result<(), std::io::Error>
248where
249 T: Encodable + ?Sized,
250 W: std::io::Write,
251{
252 let mut encoder = object.encoder();
253 flush_to_writer(&mut encoder, writer)
254}
255
256/// Flushes the output of an [`Encoder`] to a standard I/O writer.
257///
258/// See [`encode_to_writer`] for more information.
259///
260/// # Errors
261///
262/// Returns any I/O error encountered while writing to the writer.
263#[cfg(feature = "std")]
264pub fn flush_to_writer<T, W>(encoder: &mut T, mut writer: W) -> Result<(), std::io::Error>
265where
266 T: Encoder + ?Sized,
267 W: std::io::Write,
268{
269 loop {
270 writer.write_all(encoder.current_chunk())?;
271 if !encoder.advance() {
272 break;
273 }
274 }
275 Ok(())
276}
277
278impl<T: Encoder> Encoder for Option<T> {
279 fn current_chunk(&self) -> &[u8] {
280 match self {
281 Some(encoder) => encoder.current_chunk(),
282 None => &[],
283 }
284 }
285
286 fn advance(&mut self) -> bool {
287 match self {
288 Some(encoder) => encoder.advance(),
289 None => false,
290 }
291 }
292}
293
294impl<T: Encoder + ExactSizeEncoder> ExactSizeEncoder for Option<T> {
295 fn len(&self) -> usize {
296 self.as_ref().map_or(0, ExactSizeEncoder::len)
297 }
298}