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
152/// An encoder for a list of consensus encodable types, including a length prefix.
153pub struct PrefixedSliceEncoder<'e, T: Encode>(Encoder2<CompactSizeEncoder, SliceEncoder<'e, T>>);
154
155impl<'e, T: Encode> PrefixedSliceEncoder<'e, T> {
156    /// Constructs an encoder which encodes the slice, adding the length prefix.
157    #[inline]
158    pub fn new(sl: &'e [T]) -> Self {
159        Self(Encoder2::new(
160            CompactSizeEncoder::new(sl.len()),
161            SliceEncoder::without_length_prefix(sl),
162        ))
163    }
164}
165
166impl<'e, T: Encode + 'e> fmt::Debug for PrefixedSliceEncoder<'e, T>
167where
168    T::Encoder<'e>: fmt::Debug,
169{
170    #[inline]
171    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) }
172}
173
174impl<'e, T: Encode + 'e> Clone for PrefixedSliceEncoder<'e, T>
175where
176    T::Encoder<'e>: Clone,
177{
178    #[inline]
179    fn clone(&self) -> Self { Self(self.0.clone()) }
180}
181
182impl<T: Encode> Encoder for PrefixedSliceEncoder<'_, T> {
183    #[inline]
184    fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
185
186    #[inline]
187    fn advance(&mut self) -> EncoderStatus { self.0.advance() }
188}
189
190/// Helper macro to define an unrolled `EncoderN` composite encoder.
191macro_rules! define_encoder_n {
192    (
193        $(#[$attr:meta])*
194        $name:ident, $idx_limit:literal;
195        $(($enc_idx:literal, $enc_ty:ident, $enc_field:ident),)*
196    ) => {
197        $(#[$attr])*
198        #[derive(Debug, Clone)]
199        pub struct $name<$($enc_ty,)*> {
200            cur_idx: usize,
201            $($enc_field: $enc_ty,)*
202        }
203
204        impl<$($enc_ty,)*> $name<$($enc_ty,)*> {
205            /// Constructs a new composite encoder.
206            pub const fn new($($enc_field: $enc_ty,)*) -> Self {
207                Self { cur_idx: 0, $($enc_field,)* }
208            }
209        }
210
211        impl<$($enc_ty: Encoder,)*> Encoder for $name<$($enc_ty,)*> {
212            #[inline]
213            fn current_chunk(&self) -> &[u8] {
214                match self.cur_idx {
215                    $($enc_idx => self.$enc_field.current_chunk(),)*
216                    _ => unreachable!("index never reaches this value"),
217                }
218            }
219
220            #[inline]
221            fn advance(&mut self) -> EncoderStatus {
222                match self.cur_idx {
223                    $(
224                        $enc_idx => {
225                            // For the last encoder, just pass through
226                            if $enc_idx == $idx_limit - 1 {
227                                return self.$enc_field.advance()
228                            }
229                            // For all others, return EncoderStatus::HasMore, or increment to next encoder
230                            if self.$enc_field.advance().has_finished() {
231                                self.cur_idx += 1;
232                            }
233                            EncoderStatus::HasMore
234                        }
235                    )*
236                    _ => EncoderStatus::Finished,
237                }
238            }
239        }
240
241        impl<$($enc_ty,)*> ExactSizeEncoder for $name<$($enc_ty,)*>
242        where
243            $($enc_ty: Encoder + ExactSizeEncoder,)*
244        {
245            #[inline]
246            fn len(&self) -> usize {
247                0 $(+ self.$enc_field.len())*
248            }
249        }
250    };
251}
252
253define_encoder_n! {
254    /// An encoder which encodes two objects, one after the other.
255    Encoder2, 2;
256    (0, A, enc_1), (1, B, enc_2),
257}
258
259define_encoder_n! {
260    /// An encoder which encodes three objects, one after the other.
261    Encoder3, 3;
262    (0, A, enc_1), (1, B, enc_2), (2, C, enc_3),
263}
264
265define_encoder_n! {
266    /// An encoder which encodes four objects, one after the other.
267    Encoder4, 4;
268    (0, A, enc_1), (1, B, enc_2),
269    (2, C, enc_3), (3, D, enc_4),
270}
271
272define_encoder_n! {
273    /// An encoder which encodes six objects, one after the other.
274    Encoder6, 6;
275    (0, A, enc_1), (1, B, enc_2), (2, C, enc_3),
276    (3, D, enc_4), (4, E, enc_5), (5, F, enc_6),
277}