Skip to main content

bitcoin_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::Encode`]
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::{Encode, Encoder, EncoderStatus, ExactSizeEncoder};
16use crate::CompactSizeEncoder;
17
18/// An encoder for a single byte slice.
19#[derive(Debug, Clone)]
20pub struct BytesEncoder<'sl> {
21    sl: &'sl [u8],
22}
23
24impl<'sl> BytesEncoder<'sl> {
25    /// Constructs a byte encoder which encodes the given byte slice, with no length prefix.
26    pub const fn without_length_prefix(sl: &'sl [u8]) -> Self { Self { sl } }
27}
28
29impl Encoder for BytesEncoder<'_> {
30    fn current_chunk(&self) -> &[u8] { self.sl }
31
32    fn advance(&mut self) -> EncoderStatus { EncoderStatus::Finished }
33}
34
35impl<'sl> ExactSizeEncoder for BytesEncoder<'sl> {
36    #[inline]
37    fn len(&self) -> usize { self.sl.len() }
38}
39
40/// An encoder for a single byte slice, including a compact size length prefix.
41#[derive(Debug, Clone)]
42pub struct PrefixedBytesEncoder<'sl>(Encoder2<CompactSizeEncoder, BytesEncoder<'sl>>);
43
44impl<'sl> PrefixedBytesEncoder<'sl> {
45    /// Constructs a byte encoder which encodes the given byte slice, with a length prefix.
46    #[inline]
47    pub fn new(sl: &'sl [u8]) -> Self {
48        Self(Encoder2::new(
49            CompactSizeEncoder::new(sl.len()),
50            BytesEncoder::without_length_prefix(sl),
51        ))
52    }
53}
54
55impl Encoder for PrefixedBytesEncoder<'_> {
56    #[inline]
57    fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
58
59    #[inline]
60    fn advance(&mut self) -> EncoderStatus { self.0.advance() }
61}
62
63impl ExactSizeEncoder for PrefixedBytesEncoder<'_> {
64    #[inline]
65    fn len(&self) -> usize { self.0.len() }
66}
67
68/// An encoder for a single array.
69#[derive(Debug, Clone)]
70pub struct ArrayEncoder<const N: usize> {
71    arr: [u8; N],
72}
73
74impl<const N: usize> ArrayEncoder<N> {
75    /// Constructs an encoder which encodes the array with no length prefix.
76    pub const fn without_length_prefix(arr: [u8; N]) -> Self { Self { arr } }
77}
78
79impl<const N: usize> Encoder for ArrayEncoder<N> {
80    #[inline]
81    fn current_chunk(&self) -> &[u8] { &self.arr }
82
83    #[inline]
84    fn advance(&mut self) -> EncoderStatus { EncoderStatus::Finished }
85}
86
87impl<const N: usize> ExactSizeEncoder for ArrayEncoder<N> {
88    #[inline]
89    fn len(&self) -> usize { self.arr.len() }
90}
91
92/// An encoder for a reference to an array.
93///
94/// This encoder borrows the array instead of taking ownership, avoiding a copy
95/// when the array is already available by reference (e.g., as a struct field).
96#[derive(Debug, Clone)]
97pub struct ArrayRefEncoder<'e, const N: usize> {
98    arr: &'e [u8; N],
99}
100
101impl<'e, const N: usize> ArrayRefEncoder<'e, N> {
102    /// Constructs an encoder which encodes the array reference with no length prefix.
103    pub const fn without_length_prefix(arr: &'e [u8; N]) -> Self { Self { arr } }
104}
105
106impl<const N: usize> Encoder for ArrayRefEncoder<'_, N> {
107    #[inline]
108    fn current_chunk(&self) -> &[u8] { self.arr }
109
110    #[inline]
111    fn advance(&mut self) -> EncoderStatus { EncoderStatus::Finished }
112}
113
114impl<const N: usize> ExactSizeEncoder for ArrayRefEncoder<'_, N> {
115    #[inline]
116    fn len(&self) -> usize { self.arr.len() }
117}
118
119/// An encoder for a list of encodable types.
120pub struct SliceEncoder<'e, T: Encode> {
121    /// The list of references to the objects we are encoding.
122    sl: &'e [T],
123    /// Encoder for the current object being encoded.
124    cur_enc: Option<T::Encoder<'e>>,
125}
126
127impl<'e, T: Encode> SliceEncoder<'e, T> {
128    /// Constructs an encoder which encodes the slice _without_ adding the length prefix.
129    ///
130    /// To encode with a length prefix, use [`PrefixedSliceEncoder`] instead.
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: Encode> 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: Encode> Clone for SliceEncoder<'e, T>
154where
155    T::Encoder<'e>: Clone,
156{
157    fn clone(&self) -> Self { Self { sl: self.sl, cur_enc: self.cur_enc.clone() } }
158}
159
160impl<T: Encode> Encoder for SliceEncoder<'_, T> {
161    fn current_chunk(&self) -> &[u8] {
162        // `advance` sets `cur_enc` to `None` once the slice encoder is completely exhausted.
163        self.cur_enc.as_ref().map(T::Encoder::current_chunk).unwrap_or_default()
164    }
165
166    fn advance(&mut self) -> EncoderStatus {
167        let Some(cur) = self.cur_enc.as_mut() else {
168            return EncoderStatus::Finished;
169        };
170
171        loop {
172            // On subsequent calls, attempt to advance the current encoder and return
173            // success if this succeeds.
174            if cur.advance().has_more() {
175                return EncoderStatus::HasMore;
176            }
177            // self.sl guaranteed to be non-empty if cur is non-None.
178            self.sl = &self.sl[1..];
179
180            // If advancing the current encoder failed, attempt to move to the next encoder.
181            if let Some(x) = self.sl.first() {
182                *cur = x.encoder();
183                if !cur.current_chunk().is_empty() {
184                    return EncoderStatus::HasMore;
185                }
186            } else {
187                self.cur_enc = None; // shortcut the next call to advance()
188                return EncoderStatus::Finished;
189            }
190        }
191    }
192}
193
194/// An encoder for a list of encodable types, including a length prefix.
195pub struct PrefixedSliceEncoder<'e, T: Encode>(Encoder2<CompactSizeEncoder, SliceEncoder<'e, T>>);
196
197impl<'e, T: Encode> PrefixedSliceEncoder<'e, T> {
198    /// Constructs an encoder which encodes the slice, adding the length prefix.
199    #[inline]
200    pub fn new(sl: &'e [T]) -> Self {
201        Self(Encoder2::new(
202            CompactSizeEncoder::new(sl.len()),
203            SliceEncoder::without_length_prefix(sl),
204        ))
205    }
206}
207
208impl<'e, T: Encode> fmt::Debug for PrefixedSliceEncoder<'e, T>
209where
210    T::Encoder<'e>: fmt::Debug,
211{
212    #[inline]
213    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
214}
215
216impl<'e, T: Encode> Clone for PrefixedSliceEncoder<'e, T>
217where
218    T::Encoder<'e>: Clone,
219{
220    #[inline]
221    fn clone(&self) -> Self { Self(self.0.clone()) }
222}
223
224impl<T: Encode> Encoder for PrefixedSliceEncoder<'_, T> {
225    #[inline]
226    fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
227
228    #[inline]
229    fn advance(&mut self) -> EncoderStatus { self.0.advance() }
230}
231
232/// Helper macro to define an unrolled `EncoderN` composite encoder.
233macro_rules! define_encoder_n {
234    (
235        $(#[$attr:meta])*
236        $name:ident, $idx_limit:literal;
237        $(($enc_idx:literal, $enc_ty:ident, $enc_field:ident),)*
238    ) => {
239        $(#[$attr])*
240        #[derive(Debug, Clone)]
241        pub struct $name<$($enc_ty,)*> {
242            cur_idx: usize,
243            $($enc_field: $enc_ty,)*
244        }
245
246        impl<$($enc_ty,)*> $name<$($enc_ty,)*> {
247            /// Constructs a new composite encoder.
248            pub const fn new($($enc_field: $enc_ty,)*) -> Self {
249                Self { cur_idx: 0, $($enc_field,)* }
250            }
251        }
252
253        impl<$($enc_ty: Encoder,)*> Encoder for $name<$($enc_ty,)*> {
254            #[inline]
255            fn current_chunk(&self) -> &[u8] {
256                match self.cur_idx {
257                    $($enc_idx => self.$enc_field.current_chunk(),)*
258                    _ => unreachable!("index never reaches this value"),
259                }
260            }
261
262            #[inline]
263            fn advance(&mut self) -> EncoderStatus {
264                match self.cur_idx {
265                    $(
266                        $enc_idx => {
267                            // For the last encoder, just pass through
268                            if $enc_idx == $idx_limit - 1 {
269                                return self.$enc_field.advance()
270                            }
271                            // For all others, return EncoderStatus::HasMore, or increment to next encoder
272                            if self.$enc_field.advance().has_finished() {
273                                self.cur_idx += 1;
274                            }
275                            EncoderStatus::HasMore
276                        }
277                    )*
278                    _ => EncoderStatus::Finished,
279                }
280            }
281        }
282
283        impl<$($enc_ty,)*> ExactSizeEncoder for $name<$($enc_ty,)*>
284        where
285            $($enc_ty: Encoder + ExactSizeEncoder,)*
286        {
287            #[inline]
288            fn len(&self) -> usize {
289                0 $(+ self.$enc_field.len())*
290            }
291        }
292    };
293}
294
295define_encoder_n! {
296    /// An encoder which encodes two objects, one after the other.
297    Encoder2, 2;
298    (0, A, enc_1), (1, B, enc_2),
299}
300
301define_encoder_n! {
302    /// An encoder which encodes three objects, one after the other.
303    Encoder3, 3;
304    (0, A, enc_1), (1, B, enc_2), (2, C, enc_3),
305}
306
307define_encoder_n! {
308    /// An encoder which encodes four objects, one after the other.
309    Encoder4, 4;
310    (0, A, enc_1), (1, B, enc_2),
311    (2, C, enc_3), (3, D, enc_4),
312}
313
314define_encoder_n! {
315    /// An encoder which encodes six objects, one after the other.
316    Encoder6, 6;
317    (0, A, enc_1), (1, B, enc_2), (2, C, enc_3),
318    (3, D, enc_4), (4, E, enc_5), (5, F, enc_6),
319}