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