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