Skip to main content

tidecoin_consensus_encoding/encode/
encoders.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Collection of "standard encoders".
4//!
5//! These encoders should not be used directly. Instead, when implementing the [`super::Encodable`]
6//! trait on a type, you should define a newtype around one or more of these encoders, and pass
7//! through the [`Encoder`] implementation to your newtype. This avoids leaking encoding
8//! implementation details to the users of your type.
9//!
10//! For implementing these newtypes, we provide the [`encoder_newtype`] and
11//! [`encoder_newtype_exact`] macros.
12
13use core::fmt;
14
15use super::{Encodable, Encoder, ExactSizeEncoder};
16
17/// An encoder for a single byte slice.
18#[derive(Debug, Clone)]
19pub struct BytesEncoder<'sl> {
20    sl: Option<&'sl [u8]>,
21}
22
23impl<'sl> BytesEncoder<'sl> {
24    /// Constructs a byte encoder which encodes the given byte slice, with no length prefix.
25    pub const fn without_length_prefix(sl: &'sl [u8]) -> Self {
26        Self { sl: Some(sl) }
27    }
28}
29
30impl Encoder for BytesEncoder<'_> {
31    fn current_chunk(&self) -> &[u8] {
32        self.sl.unwrap_or_default()
33    }
34
35    fn advance(&mut self) -> bool {
36        self.sl = None;
37        false
38    }
39}
40
41impl<'sl> ExactSizeEncoder for BytesEncoder<'sl> {
42    #[inline]
43    fn len(&self) -> usize {
44        self.sl.map_or(0, <[u8]>::len)
45    }
46}
47
48/// An encoder for a single array.
49#[derive(Debug, Clone)]
50pub struct ArrayEncoder<const N: usize> {
51    arr: Option<[u8; N]>,
52}
53
54impl<const N: usize> ArrayEncoder<N> {
55    /// Constructs an encoder which encodes the array with no length prefix.
56    pub const fn without_length_prefix(arr: [u8; N]) -> Self {
57        Self { arr: Some(arr) }
58    }
59}
60
61impl<const N: usize> Encoder for ArrayEncoder<N> {
62    #[inline]
63    fn current_chunk(&self) -> &[u8] {
64        self.arr.as_ref().map(|x| &x[..]).unwrap_or_default()
65    }
66
67    #[inline]
68    fn advance(&mut self) -> bool {
69        self.arr = None;
70        false
71    }
72}
73
74impl<const N: usize> ExactSizeEncoder for ArrayEncoder<N> {
75    #[inline]
76    fn len(&self) -> usize {
77        self.arr.map_or(0, |a| a.len())
78    }
79}
80
81/// An encoder for a reference to an array.
82///
83/// This encoder borrows the array instead of taking ownership, avoiding a copy
84/// when the array is already available by reference (e.g., as a struct field).
85#[derive(Debug, Clone)]
86pub struct ArrayRefEncoder<'e, const N: usize> {
87    arr: Option<&'e [u8; N]>,
88}
89
90impl<'e, const N: usize> ArrayRefEncoder<'e, N> {
91    /// Constructs an encoder which encodes the array reference with no length prefix.
92    pub const fn without_length_prefix(arr: &'e [u8; N]) -> Self {
93        Self { arr: Some(arr) }
94    }
95}
96
97impl<const N: usize> Encoder for ArrayRefEncoder<'_, N> {
98    #[inline]
99    fn current_chunk(&self) -> &[u8] {
100        self.arr.map(|x| &x[..]).unwrap_or_default()
101    }
102
103    #[inline]
104    fn advance(&mut self) -> bool {
105        self.arr = None;
106        false
107    }
108}
109
110impl<const N: usize> ExactSizeEncoder for ArrayRefEncoder<'_, N> {
111    #[inline]
112    fn len(&self) -> usize {
113        self.arr.map_or(0, |a| a.len())
114    }
115}
116
117/// An encoder for a list of encodable types.
118pub struct SliceEncoder<'e, T: Encodable> {
119    /// The list of references to the objects we are encoding.
120    sl: &'e [T],
121    /// Encoder for the current object being encoded.
122    cur_enc: Option<T::Encoder<'e>>,
123}
124
125impl<'e, T: Encodable> SliceEncoder<'e, T> {
126    /// Constructs an encoder which encodes the slice _without_ adding the length prefix.
127    ///
128    /// To encode with a length prefix consider using [`Encoder2`].
129    ///
130    /// E.g, `Encoder2<CompactSizeEncoder, SliceEncoder<'e, Foo>>`.
131    pub fn without_length_prefix(sl: &'e [T]) -> Self {
132        // In this `map` call we cannot remove the closure. Seems to be a bug in the compiler.
133        // Perhaps https://github.com/rust-lang/rust/issues/102540 which is 3 years old with
134        // no replies or even an acknowledgement. We will not bother filing our own issue.
135        Self { sl, cur_enc: sl.first().map(|x| T::encoder(x)) }
136    }
137}
138
139impl<'e, T: Encodable> fmt::Debug for SliceEncoder<'e, T>
140where
141    T::Encoder<'e>: fmt::Debug,
142{
143    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144        f.debug_struct("SliceEncoder")
145            .field("sl", &self.sl.len())
146            .field("cur_enc", &self.cur_enc)
147            .finish()
148    }
149}
150
151// Manual impl rather than #[derive(Clone)] because derive would constrain `where T: Clone`,
152// but `T` itself is never cloned, only the associated type `T::Encoder<'e>`.
153impl<'e, T: Encodable> Clone for SliceEncoder<'e, T>
154where
155    T::Encoder<'e>: Clone,
156{
157    fn clone(&self) -> Self {
158        Self { sl: self.sl, cur_enc: self.cur_enc.clone() }
159    }
160}
161
162impl<T: Encodable> Encoder for SliceEncoder<'_, T> {
163    fn current_chunk(&self) -> &[u8] {
164        // `advance` sets `cur_enc` to `None` once the slice encoder is completely exhausted.
165        self.cur_enc.as_ref().map(T::Encoder::current_chunk).unwrap_or_default()
166    }
167
168    fn advance(&mut self) -> bool {
169        let Some(cur) = self.cur_enc.as_mut() else {
170            return false;
171        };
172
173        loop {
174            // On subsequent calls, attempt to advance the current encoder and return
175            // success if this succeeds.
176            if cur.advance() {
177                return true;
178            }
179            // self.sl guaranteed to be non-empty if cur is non-None.
180            self.sl = &self.sl[1..];
181
182            // If advancing the current encoder failed, attempt to move to the next encoder.
183            if let Some(x) = self.sl.first() {
184                *cur = x.encoder();
185                if !cur.current_chunk().is_empty() {
186                    return true;
187                }
188            } else {
189                self.cur_enc = None; // shortcut the next call to advance()
190                return false;
191            }
192        }
193    }
194}
195
196impl<'e, T> ExactSizeEncoder for SliceEncoder<'e, T>
197where
198    T: Encodable + 'e,
199    T::Encoder<'e>: ExactSizeEncoder,
200{
201    fn len(&self) -> usize {
202        let Some(cur_enc) = self.cur_enc.as_ref() else {
203            return 0;
204        };
205
206        let rest = self.sl.get(1..).unwrap_or_default().iter().map(|item| item.encoder().len());
207        cur_enc.len() + rest.sum::<usize>()
208    }
209}
210
211/// Helper macro to define an unrolled `EncoderN` composite encoder.
212macro_rules! define_encoder_n {
213    (
214        $(#[$attr:meta])*
215        $name:ident, $idx_limit:literal;
216        $(($enc_idx:literal, $enc_ty:ident, $enc_field:ident),)*
217    ) => {
218        $(#[$attr])*
219        #[derive(Debug, Clone)]
220        pub struct $name<$($enc_ty,)*> {
221            cur_idx: usize,
222            $($enc_field: $enc_ty,)*
223        }
224
225        impl<$($enc_ty,)*> $name<$($enc_ty,)*> {
226            /// Constructs a new composite encoder.
227            pub const fn new($($enc_field: $enc_ty,)*) -> Self {
228                Self { cur_idx: 0, $($enc_field,)* }
229            }
230        }
231
232        impl<$($enc_ty: Encoder,)*> Encoder for $name<$($enc_ty,)*> {
233            #[inline]
234            fn current_chunk(&self) -> &[u8] {
235                match self.cur_idx {
236                    $($enc_idx => self.$enc_field.current_chunk(),)*
237                    _ => &[],
238                }
239            }
240
241            #[inline]
242            fn advance(&mut self) -> bool {
243                match self.cur_idx {
244                    $(
245                        $enc_idx => {
246                            // For the last encoder, just pass through
247                            if $enc_idx == $idx_limit - 1 {
248                                return self.$enc_field.advance()
249                            }
250                            // For all others, return true, or increment to next encoder
251                            if !self.$enc_field.advance() {
252                                self.cur_idx += 1;
253                            }
254                            true
255                        }
256                    )*
257                    _ => false,
258                }
259            }
260        }
261
262        impl<$($enc_ty,)*> ExactSizeEncoder for $name<$($enc_ty,)*>
263        where
264            $($enc_ty: Encoder + ExactSizeEncoder,)*
265        {
266            #[inline]
267            fn len(&self) -> usize {
268                0 $(+ self.$enc_field.len())*
269            }
270        }
271    };
272}
273
274define_encoder_n! {
275    /// An encoder which encodes two objects, one after the other.
276    Encoder2, 2;
277    (0, A, enc_1), (1, B, enc_2),
278}
279
280define_encoder_n! {
281    /// An encoder which encodes three objects, one after the other.
282    Encoder3, 3;
283    (0, A, enc_1), (1, B, enc_2), (2, C, enc_3),
284}
285
286define_encoder_n! {
287    /// An encoder which encodes four objects, one after the other.
288    Encoder4, 4;
289    (0, A, enc_1), (1, B, enc_2),
290    (2, C, enc_3), (3, D, enc_4),
291}
292
293define_encoder_n! {
294    /// An encoder which encodes six objects, one after the other.
295    Encoder6, 6;
296    (0, A, enc_1), (1, B, enc_2), (2, C, enc_3),
297    (3, D, enc_4), (4, E, enc_5), (5, F, enc_6),
298}