Skip to main content

bitcoin_consensus_encoding/encode/
encoders.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Primitive and combinator encoder types.
4//!
5//! These encoders should not be used directly. Instead, you should define a newtype around one or
6//! more of these encoders, and pass through the [`Encoder`] implementation to your newtype. This
7//! avoids leaking encoding implementation details to the users of your type.
8//!
9//! For implementing these newtypes, we provide the [`encoder_newtype`] and
10//! [`encoder_newtype_exact`] macros.
11
12use core::fmt;
13
14use super::iter::{Encoders, IterEncoder};
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 consensus encodable types.
120pub struct SliceEncoder<'e, T: Encode>(IterEncoder<Encoders<'e, T>>);
121
122impl<'e, T: Encode> SliceEncoder<'e, T> {
123    /// Constructs an encoder which encodes the slice _without_ adding the length prefix.
124    ///
125    /// To encode with a length prefix, use [`PrefixedSliceEncoder`] instead.
126    pub fn without_length_prefix(sl: &'e [T]) -> Self { Self(IterEncoder::new(Encoders::new(sl))) }
127}
128
129impl<'e, T: Encode + 'e> fmt::Debug for SliceEncoder<'e, T>
130where
131    T::Encoder<'e>: fmt::Debug,
132{
133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        f.debug_tuple("SliceEncoder").field(&self.0).finish()
135    }
136}
137
138// Manual impl rather than #[derive(Clone)] because derive would constrain `where T: Clone`,
139// but `T` itself is never cloned, only the associated type `T::Encoder<'e>`.
140impl<'e, T: Encode + 'e> Clone for SliceEncoder<'e, T>
141where
142    T::Encoder<'e>: Clone,
143{
144    fn clone(&self) -> Self { Self(self.0.clone()) }
145}
146
147impl<T: Encode> Encoder for SliceEncoder<'_, T> {
148    fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
149    fn advance(&mut self) -> EncoderStatus { self.0.advance() }
150}
151
152impl<'e, T: Encode> ExactSizeEncoder for SliceEncoder<'e, T>
153where
154    T::Encoder<'e>: ExactSizeEncoder,
155{
156    #[inline]
157    fn len(&self) -> usize { self.0.len() }
158}
159
160/// An encoder for a list of consensus encodable types, including a length prefix.
161pub struct PrefixedSliceEncoder<'e, T: Encode>(Encoder2<CompactSizeEncoder, SliceEncoder<'e, T>>);
162
163impl<'e, T: Encode> PrefixedSliceEncoder<'e, T> {
164    /// Constructs an encoder which encodes the slice, adding the length prefix.
165    #[inline]
166    pub fn new(sl: &'e [T]) -> Self {
167        Self(Encoder2::new(
168            CompactSizeEncoder::new(sl.len()),
169            SliceEncoder::without_length_prefix(sl),
170        ))
171    }
172}
173
174impl<'e, T: Encode + 'e> fmt::Debug for PrefixedSliceEncoder<'e, T>
175where
176    T::Encoder<'e>: fmt::Debug,
177{
178    #[inline]
179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
180}
181
182impl<'e, T: Encode + 'e> Clone for PrefixedSliceEncoder<'e, T>
183where
184    T::Encoder<'e>: Clone,
185{
186    #[inline]
187    fn clone(&self) -> Self { Self(self.0.clone()) }
188}
189
190impl<T: Encode> Encoder for PrefixedSliceEncoder<'_, T> {
191    #[inline]
192    fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
193
194    #[inline]
195    fn advance(&mut self) -> EncoderStatus { self.0.advance() }
196}
197
198impl<'e, T: Encode> ExactSizeEncoder for PrefixedSliceEncoder<'e, T>
199where
200    T::Encoder<'e>: ExactSizeEncoder,
201{
202    #[inline]
203    fn len(&self) -> usize { self.0.len() }
204}
205
206/// Helper macro to define an unrolled `EncoderN` composite encoder.
207macro_rules! define_encoder_n {
208    (
209        $(#[$attr:meta])*
210        $name:ident, $idx_limit:literal;
211        $(($enc_idx:literal, $enc_ty:ident, $enc_field:ident),)*
212    ) => {
213        $(#[$attr])*
214        #[derive(Debug, Clone)]
215        pub struct $name<$($enc_ty,)*> {
216            cur_idx: usize,
217            $($enc_field: $enc_ty,)*
218        }
219
220        impl<$($enc_ty,)*> $name<$($enc_ty,)*> {
221            /// Constructs a new composite encoder.
222            pub const fn new($($enc_field: $enc_ty,)*) -> Self {
223                Self { cur_idx: 0, $($enc_field,)* }
224            }
225        }
226
227        impl<$($enc_ty: Encoder,)*> Encoder for $name<$($enc_ty,)*> {
228            #[inline]
229            fn current_chunk(&self) -> &[u8] {
230                match self.cur_idx {
231                    $($enc_idx => self.$enc_field.current_chunk(),)*
232                    _ => unreachable!("index never reaches this value"),
233                }
234            }
235
236            #[inline]
237            fn advance(&mut self) -> EncoderStatus {
238                match self.cur_idx {
239                    $(
240                        $enc_idx => {
241                            // For the last encoder, just pass through
242                            if $enc_idx == $idx_limit - 1 {
243                                return self.$enc_field.advance()
244                            }
245                            // For all others, return EncoderStatus::HasMore, or increment to next encoder
246                            if self.$enc_field.advance().has_finished() {
247                                self.cur_idx += 1;
248                            }
249                            EncoderStatus::HasMore
250                        }
251                    )*
252                    _ => EncoderStatus::Finished,
253                }
254            }
255        }
256
257        impl<$($enc_ty,)*> ExactSizeEncoder for $name<$($enc_ty,)*>
258        where
259            $($enc_ty: Encoder + ExactSizeEncoder,)*
260        {
261            #[inline]
262            fn len(&self) -> usize {
263                let mut total = 0;
264                $(if self.cur_idx <= $enc_idx { total += self.$enc_field.len(); })*
265                total
266            }
267        }
268    };
269}
270
271define_encoder_n! {
272    /// An encoder which encodes two objects, one after the other.
273    Encoder2, 2;
274    (0, A, enc_1), (1, B, enc_2),
275}
276
277define_encoder_n! {
278    /// An encoder which encodes three objects, one after the other.
279    Encoder3, 3;
280    (0, A, enc_1), (1, B, enc_2), (2, C, enc_3),
281}
282
283define_encoder_n! {
284    /// An encoder which encodes four objects, one after the other.
285    Encoder4, 4;
286    (0, A, enc_1), (1, B, enc_2),
287    (2, C, enc_3), (3, D, enc_4),
288}
289
290define_encoder_n! {
291    /// An encoder which encodes six objects, one after the other.
292    Encoder6, 6;
293    (0, A, enc_1), (1, B, enc_2), (2, C, enc_3),
294    (3, D, enc_4), (4, E, enc_5), (5, F, enc_6),
295}