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}