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