Skip to main content

bitcoin_consensus_encoding/encode/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Consensus Encoding Traits
4
5#[cfg(feature = "alloc")]
6#[cfg(feature = "hex")]
7use alloc::string::String;
8#[cfg(feature = "alloc")]
9use alloc::vec::Vec;
10
11pub mod encoders;
12
13/// A Bitcoin object which can be consensus-encoded.
14///
15/// To encode something, use the [`Self::encoder`] method to obtain a [`Self::Encoder`], which will
16/// behave like an iterator yielding byte slices.
17///
18/// # Examples
19///
20/// ```
21/// # #[cfg(feature = "alloc")] {
22/// use bitcoin_consensus_encoding::{encoder_newtype, encode_to_vec, Encode, ArrayEncoder};
23///
24/// struct Foo([u8; 4]);
25///
26/// encoder_newtype! {
27///     pub struct FooEncoder<'e>(ArrayEncoder<4>);
28/// }
29///
30/// impl Encode for Foo {
31///     type Encoder<'e> = FooEncoder<'e> where Self: 'e;
32///
33///     fn encoder(&self) -> Self::Encoder<'_> {
34///         FooEncoder::new(ArrayEncoder::without_length_prefix(self.0))
35///     }
36/// }
37///
38/// let foo = Foo([0xde, 0xad, 0xbe, 0xef]);
39/// assert_eq!(encode_to_vec(&foo), vec![0xde, 0xad, 0xbe, 0xef]);
40/// # }
41/// ```
42pub trait Encode {
43    /// The encoder associated with this type. Conceptually, the encoder is like
44    /// an iterator which yields byte slices.
45    type Encoder<'e>: Encoder
46    where
47        Self: 'e;
48
49    /// Constructs a "default encoder" for the type.
50    fn encoder(&self) -> Self::Encoder<'_>;
51}
52
53/// An encoder for a consensus-encodable object.
54///
55/// The consumers of a type implementing this encoder trait should generally use it in a loop like
56/// this:
57///
58/// ```no-compile
59/// loop {
60///     process_current_chunk(encoder.current_chunk());
61///     if encoder.advance().is_finished() {
62///         break
63///     }
64/// }
65/// // do NOT use encoder after this point
66/// ```
67///
68/// Processing the chunks in an equivalent state machine (presumably future) is also permissible.
69///
70/// It is crucial that the callers use the methods in that order: obtain the slice via
71/// `current_chunk`, write it somewhere and, once fully written, try to advance the encoder.
72/// Attempting to call any method after [`advance`](Self::advance) returned
73/// `EncoderStatus::Finished` or calling `advance` before fully processing the chunks will lead to
74/// unspecified buggy behavior.
75///
76/// The callers MUST NOT assume that the encoder returns any particular size of the chunks. The
77/// implementors are allowed to change the sizes of the chunks as long as the concatenation of all
78/// the bytes returned stays the same.
79pub trait Encoder {
80    /// Yields the current encoded byte slice.
81    ///
82    /// Will always return the same value until [`Self::advance`] is called.
83    /// May return an empty slice, however implementors should avoid returning empty slices unless
84    /// the encoded type is truly empty.
85    fn current_chunk(&self) -> &[u8];
86
87    /// Moves the encoder to its next state.
88    ///
89    /// Does not need to be called when the encoder is first created. (In fact, if it
90    /// is called, this will discard the first chunk of encoded data.)
91    ///
92    /// # Returns
93    ///
94    /// - `EncoderStatus::HasMore` if the encoder has advanced to a new state and [`Self::current_chunk`] will return new data.
95    /// - `EncoderStatus::Finished` if the encoder is exhausted and has no more states.
96    ///
97    /// # Important
98    ///
99    /// After `EncoderStatus::Finished` was returned the encoder is in unspecified state. Calling
100    /// any of its methods in such state is a bug (but not UB) unless the specific encoder documents
101    /// otherwise. While usually the encoder simply stays in the last possible state this MUST NOT
102    /// be relied upon by the callers.
103    fn advance(&mut self) -> EncoderStatus;
104}
105
106/// Indicates whether the encoder still has bytes available or it is finished.
107///
108/// This is returned from the [`Encoder::advance`] method to indicate whether encoding should stop
109/// or continue.
110#[derive(Debug, Copy, Clone, Eq, PartialEq)]
111#[must_use = "encoding has to stop when Finished is returned"]
112pub enum EncoderStatus {
113    /// The encoder has more bytes available (not yet finished).
114    ///
115    /// The [`current_chunk`](Encoder::current_chunk) method should be called to obtain them and
116    /// write them out after which [`advance`](Encoder::advance) should be called again to obtain
117    /// the next chunk (if any).
118    HasMore,
119
120    /// The encoding has ended, no more bytes are available.
121    ///
122    /// No encoder methods (other than drop) may be called after this variant is returned.
123    Finished,
124}
125
126impl EncoderStatus {
127    /// Returns `true` if `self` is `HasMore`, `false` otherwise.
128    pub fn has_more(&self) -> bool { matches!(self, Self::HasMore) }
129
130    /// Returns `true` if `self` is `Finished`, `false` otherwise.
131    pub fn has_finished(&self) -> bool { matches!(self, Self::Finished) }
132}
133
134/// Implements a newtype around an encoder.
135///
136/// The new type will implement the [`Encoder`] trait by forwarding to the wrapped encoder. If your
137/// type has a known size consider using [`crate::encoder_newtype_exact`] instead.
138///
139/// # Examples
140/// ```
141/// use bitcoin_consensus_encoding::{encoder_newtype, BytesEncoder};
142///
143/// encoder_newtype! {
144///     /// The encoder for the [`Foo`] type.
145///     pub struct FooEncoder<'e>(BytesEncoder<'e>);
146/// }
147/// ```
148///
149/// For a full example see `./examples/encoder.rs`.
150#[macro_export]
151macro_rules! encoder_newtype {
152    (
153        $(#[$($struct_attr:tt)*])*
154        $vis:vis struct $name:ident<$lt:lifetime>($encoder:ty);
155    ) => {
156        $(#[$($struct_attr)*])*
157        $vis struct $name<$lt>($encoder, core::marker::PhantomData<&$lt $encoder>);
158
159        #[allow(clippy::type_complexity)]
160        impl<$lt> $name<$lt> {
161            /// Constructs a new instance of the newtype encoder.
162            pub(crate) const fn new(encoder: $encoder) -> $name<$lt> {
163                $name(encoder, core::marker::PhantomData)
164            }
165        }
166
167        impl<$lt> $crate::Encoder for $name<$lt> {
168            #[inline]
169            fn current_chunk(&self) -> &[u8] { self.0.current_chunk() }
170
171            #[inline]
172            fn advance(&mut self) -> $crate::EncoderStatus { self.0.advance() }
173        }
174    }
175}
176
177/// Implements a newtype around an exact-size encoder.
178///
179/// The new type will implement both the [`Encoder`] and [`ExactSizeEncoder`] traits
180/// by forwarding to the wrapped encoder.
181///
182/// # Examples
183/// ```
184/// use bitcoin_consensus_encoding::{encoder_newtype_exact, ArrayEncoder};
185///
186/// encoder_newtype_exact! {
187///     /// The encoder for the [`Bar`] type.
188///     pub struct BarEncoder<'e>(ArrayEncoder<32>);
189/// }
190/// ```
191///
192/// For a full example see `./examples/encoder.rs`.
193#[macro_export]
194macro_rules! encoder_newtype_exact {
195    (
196        $(#[$($struct_attr:tt)*])*
197        $vis:vis struct $name:ident<$lt:lifetime>($encoder:ty);
198    ) => {
199        $crate::encoder_newtype! {
200            $(#[$($struct_attr)*])*
201            $vis struct $name<$lt>($encoder);
202        }
203
204        impl<$lt> $crate::ExactSizeEncoder for $name<$lt> {
205            #[inline]
206            fn len(&self) -> usize { self.0.len() }
207        }
208    }
209}
210
211/// Yields bytes from any [`Encoder`] instance.
212///
213/// **Important** this iterator is **not** fused! Call `fuse` if you need it to be fused.
214#[derive(Debug, Clone)]
215pub struct EncoderByteIter<T: Encoder> {
216    enc: T,
217    position: usize,
218}
219
220impl<T: Encoder> EncoderByteIter<T> {
221    /// Constructs a new byte iterator around a provided encoder.
222    pub fn new(encoder: T) -> Self { Self { enc: encoder, position: 0 } }
223
224    /// Returns the remaining bytes in the next non-empty chunk.
225    ///
226    /// The returned value is either a non-empty chunk of bytes that were not yielded yet,
227    /// immediately following the already-yielded bytes or empty slice if the encoder finished.
228    ///
229    /// This call can be paired with `nth` to mark bytes as processed.
230    ///
231    /// Just like with encoders or this iterator, attempting to use this type after this method
232    /// returned an empty slice will lead to unspecified behavior and is considered a bug in the
233    /// caller.
234    pub fn peek_chunk(&mut self) -> &[u8] {
235        // Can't use `.get(self.position..)` due to borrowck bug.
236        if self.position < self.enc.current_chunk().len() {
237            &self.enc.current_chunk()[self.position..]
238        } else {
239            loop {
240                if self.enc.advance().has_finished() {
241                    return &[];
242                }
243                if !self.enc.current_chunk().is_empty() {
244                    self.position = 0;
245                    return self.enc.current_chunk();
246                }
247            }
248        }
249    }
250}
251
252impl<T: Encoder> Iterator for EncoderByteIter<T> {
253    type Item = u8;
254
255    fn next(&mut self) -> Option<Self::Item> {
256        loop {
257            if let Some(b) = self.enc.current_chunk().get(self.position) {
258                // length of slice is guaranteed to be at most `isize::MAX` thus is `n` so this cannot
259                // overflow.
260                self.position += 1;
261                return Some(*b);
262            } else if self.enc.advance().has_finished() {
263                return None;
264            }
265            self.position = 0;
266        }
267    }
268
269    fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
270        // This could be in a loop but we intentionally unroll one iteration so that addition is
271        // only required at the beginning.
272        if let Some(b) =
273            self.position.checked_add(n).and_then(|pos| self.enc.current_chunk().get(pos))
274        {
275            // length of slice is guaranteed to be at most `isize::MAX` thus is `n` so this cannot
276            // overflow.
277            self.position += n + 1;
278            return Some(*b);
279        }
280        n -= self.enc.current_chunk().len() - self.position;
281        if self.enc.advance().has_finished() {
282            return None;
283        }
284        loop {
285            if let Some(b) = self.enc.current_chunk().get(n) {
286                self.position = n + 1;
287                return Some(*b);
288            }
289            n -= self.enc.current_chunk().len();
290            if self.enc.advance().has_finished() {
291                return None;
292            }
293        }
294    }
295}
296
297impl<T> ExactSizeIterator for EncoderByteIter<T>
298where
299    T: Encoder + ExactSizeEncoder,
300{
301    fn len(&self) -> usize { self.enc.len() - self.position }
302}
303
304/// An encoder with a known size.
305pub trait ExactSizeEncoder: Encoder {
306    /// The number of bytes remaining that the encoder will yield.
307    ///
308    /// **Important**: returns an unspecified value if [`Encoder::advance`] has returned
309    /// `EncoderStatus::Finished`.
310    fn len(&self) -> usize;
311
312    /// Returns whether the encoder would yield an empty response.
313    ///
314    /// **Important**: returns an unspecified value if [`Encoder::advance`] has returned
315    /// `EncoderStatus::Finished`.
316    fn is_empty(&self) -> bool { self.len() == 0 }
317}
318
319/// Encodes an object into a vector.
320#[cfg(feature = "alloc")]
321pub fn encode_to_vec<T>(object: &T) -> Vec<u8>
322where
323    T: Encode + ?Sized,
324{
325    let mut encoder = object.encoder();
326    drain_to_vec(&mut encoder)
327}
328
329/// Drains the output of an [`Encoder`] into a vector.
330#[cfg(feature = "alloc")]
331pub fn drain_to_vec<T>(encoder: &mut T) -> Vec<u8>
332where
333    T: Encoder + ?Sized,
334{
335    let mut vec = Vec::new();
336    loop {
337        vec.extend_from_slice(encoder.current_chunk());
338        if encoder.advance().has_finished() {
339            break;
340        }
341    }
342    vec
343}
344
345/// Encodes an object into a hex string.
346#[cfg(feature = "alloc")]
347#[cfg(feature = "hex")]
348pub fn encode_to_hex<T>(object: &T, case: hex::Case) -> String
349where
350    T: Encode + ?Sized,
351{
352    drain_to_hex(object.encoder(), case)
353}
354
355/// Drains the output of an [`Encoder`] into a hex string.
356#[cfg(feature = "alloc")]
357#[cfg(feature = "hex")]
358pub fn drain_to_hex<T>(encoder: T, case: hex::Case) -> String
359where
360    T: Encoder,
361{
362    let iter = EncoderByteIter::new(encoder);
363    let hex_iter = hex::BytesToHexIter::new(iter, case);
364    hex_iter.flatten().map(char::from).collect()
365}
366
367/// Encodes an object to a standard I/O writer.
368///
369/// # Performance
370///
371/// This method writes data in potentially small chunks based on the encoder's internal chunking
372/// strategy. For optimal performance with unbuffered writers (like [`std::fs::File`] or
373/// [`std::net::TcpStream`]), consider wrapping your writer with [`std::io::BufWriter`].
374///
375/// # Errors
376///
377/// Returns any I/O error encountered while writing to the writer.
378#[cfg(feature = "std")]
379pub fn encode_to_writer<T, W>(object: &T, writer: W) -> Result<(), std::io::Error>
380where
381    T: Encode + ?Sized,
382    W: std::io::Write,
383{
384    let mut encoder = object.encoder();
385    drain_to_writer(&mut encoder, writer)
386}
387
388/// Drains the output of an [`Encoder`] to a standard I/O writer.
389///
390/// See [`encode_to_writer`] for more information.
391///
392/// # Errors
393///
394/// Returns any I/O error encountered while writing to the writer.
395#[cfg(feature = "std")]
396pub fn drain_to_writer<T, W>(encoder: &mut T, mut writer: W) -> Result<(), std::io::Error>
397where
398    T: Encoder + ?Sized,
399    W: std::io::Write,
400{
401    loop {
402        writer.write_all(encoder.current_chunk())?;
403        if encoder.advance().has_finished() {
404            break;
405        }
406    }
407    Ok(())
408}
409
410/// Checks that the given `value` encodes to `expected`, panicking if it doesn't.
411///
412/// Note that the function does not impose any requirements on chunking - whether the encoded bytes
413/// are returned as a few large chunks or they are many smaller chunks makes no difference (other
414/// than potentially performance difference), as long as the bytes yielded are what is expected, in
415/// the correct order.
416///
417/// This is intended for tests only.
418///
419/// # Panics
420///
421/// If the bytes yielded from the encoder of `value` don't match the bytes in `expected`.
422#[track_caller]
423pub fn check_encode<T: Encode + ?Sized>(value: &T, expected: &[u8]) {
424    check_encoder(&mut value.encoder(), expected);
425}
426
427/// Checks that the given `encoder` yields `expected`, panicking if it doesn't.
428///
429/// Note that the function does not impose any requirements on chunking - whether the encoded bytes
430/// are returned as a few large chunks or they are many smaller chunks makes no difference (other
431/// than potentially performance difference), as long as the bytes yielded are what is expected, in
432/// the correct order.
433///
434/// This is intended for tests only.
435///
436/// # Panics
437///
438/// If the bytes yielded from the encoder don't match the bytes in `expected`.
439#[track_caller]
440pub fn check_encoder<T: Encoder + ?Sized>(encoder: &mut T, mut expected: &[u8]) {
441    let orig_expected_len = expected.len();
442    let mut chunk_number = 0usize;
443    let mut bytes_processed = 0usize;
444
445    loop {
446        let chunk = encoder.current_chunk();
447        assert!(
448            chunk.len() <= expected.len(),
449            "encoder yielded more bytes ({}) than expected ({})",
450            bytes_processed + chunk.len(),
451            orig_expected_len
452        );
453        if let Some((i, _)) =
454            chunk.iter().zip(&expected[..chunk.len()]).enumerate().find(|&(_, (a, b))| a != b)
455        {
456            panic!(
457                "encoder did not yield expected bytes - difference in chunk #{}, after {} bytes",
458                chunk_number,
459                bytes_processed + i
460            );
461        }
462        bytes_processed += chunk.len();
463        expected = &expected[chunk.len()..];
464        chunk_number += 1;
465        if encoder.advance().has_finished() {
466            break;
467        }
468    }
469    assert!(
470        expected.is_empty(),
471        "encoder did not yield enough bytes - {} more expected",
472        expected.len()
473    );
474}
475
476impl<T: Encoder> Encoder for Option<T> {
477    fn current_chunk(&self) -> &[u8] {
478        match self {
479            Some(encoder) => encoder.current_chunk(),
480            None => &[],
481        }
482    }
483
484    fn advance(&mut self) -> EncoderStatus {
485        match self {
486            Some(encoder) => encoder.advance(),
487            None => EncoderStatus::Finished,
488        }
489    }
490}
491
492impl<T: ExactSizeEncoder> ExactSizeEncoder for Option<T> {
493    fn len(&self) -> usize {
494        match self {
495            Some(encoder) => encoder.len(),
496            None => 0,
497        }
498    }
499}