bitcoin_consensus_encoding/decode/mod.rs
1// SPDX-License-Identifier: CC0-1.0
2
3//! Consensus Decoding Traits
4
5pub mod decoders;
6
7#[cfg(feature = "std")]
8use crate::ReadError;
9use crate::{DecodeError, UnconsumedError};
10
11/// A Bitcoin object which can be consensus-decoded using a push decoder.
12///
13/// To decode something, create a [`Self::Decoder`] and push byte slices into it with
14/// [`Decoder::push_bytes`], then call [`Decoder::end`] to get the result.
15///
16/// # Examples
17///
18/// ```
19/// use bitcoin_consensus_encoding::{decode_from_slice, Decode, Decoder, DecoderStatus, ArrayDecoder, UnexpectedEofError};
20///
21/// struct Foo([u8; 4]);
22///
23/// #[derive(Default)]
24/// struct FooDecoder(ArrayDecoder<4>);
25///
26/// impl Decoder for FooDecoder {
27/// type Output = Foo;
28/// type Error = UnexpectedEofError;
29///
30/// fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<DecoderStatus, Self::Error> {
31/// self.0.push_bytes(bytes)
32/// }
33/// fn end(self) -> Result<Self::Output, Self::Error> { self.0.end().map(Foo) }
34/// fn read_limit(&self) -> usize { self.0.read_limit() }
35/// }
36///
37/// impl Decode for Foo {
38/// type Decoder = FooDecoder;
39/// }
40///
41/// let foo: Foo = decode_from_slice(&[0xde, 0xad, 0xbe, 0xef]).unwrap();
42/// assert_eq!(foo.0, [0xde, 0xad, 0xbe, 0xef]);
43/// ```
44pub trait Decode {
45 /// Associated decoder for the type.
46 type Decoder: Decoder<Output = Self> + Default;
47
48 /// Constructs a "default decoder" for the type.
49 fn decoder() -> Self::Decoder { Self::Decoder::default() }
50}
51
52/// A push decoder for a consensus-decodable object.
53pub trait Decoder: Sized {
54 /// The type that this decoder produces when decoding is complete.
55 type Output;
56 /// The error type that this decoder can produce.
57 type Error;
58
59 /// Pushes bytes into the decoder, consuming as much as possible.
60 ///
61 /// The slice reference will be advanced to point to the unconsumed portion. Returns
62 /// `Ok(DecoderStatus::NeedsMore)` if more bytes are needed to complete decoding,
63 /// `Ok(DecoderStatus::Ready)` if the decoder is ready to finalize with [`Self::end`], or
64 /// `Err(error)` if parsing failed.
65 ///
66 /// Once the decoder returns `Ok(DecoderStatus::Ready)`, subsequent calls to this method will
67 /// continue to return `Ok(DecoderStatus::Ready)` without consuming additional bytes.
68 ///
69 /// # Errors
70 ///
71 /// Returns an error if the provided bytes are invalid or malformed according to the decoder's
72 /// validation rules. Insufficient data (needing more bytes) is *not* an error for this method,
73 /// the decoder will simply consume what it can and return `DecoderStatus::NeedsMore` to
74 /// indicate more data is needed.
75 ///
76 /// # Panics
77 ///
78 /// May panic if called after a previous call to [`Self::push_bytes`] errored.
79 #[must_use = "must check result to avoid panics on subsequent calls"]
80 #[track_caller]
81 fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<DecoderStatus, Self::Error>;
82
83 /// Completes the decoding process and returns the final result.
84 ///
85 /// This consumes the decoder and should be called when no more input data is available.
86 ///
87 /// # Errors
88 ///
89 /// Returns an error if the decoder has not received sufficient data to complete decoding, or if
90 /// the accumulated data is invalid when considered as a complete object.
91 ///
92 /// # Panics
93 ///
94 /// May panic if called after a previous call to [`Self::push_bytes`] errored.
95 #[must_use = "must check result to avoid panics on subsequent calls"]
96 #[track_caller]
97 fn end(self) -> Result<Self::Output, Self::Error>;
98
99 /// Returns the maximum number of bytes this decoder can consume without over-reading.
100 ///
101 /// Returns 0 if the decoder is complete and ready to finalize with [`Self::end`]. This is used
102 /// by [`decode_from_read_unbuffered`] to optimize read sizes, avoiding both inefficient
103 /// under-reads and unnecessary over-reads.
104 fn read_limit(&self) -> usize;
105}
106
107/// Indicates whether a decoder needs more data or is ready to finalize.
108///
109/// This is returned from the [`Decoder::push_bytes`] method to indicate whether the decoder
110/// should continue accumulating data or is ready to produce the decoded value with [`Decoder::end`].
111#[derive(Debug, Copy, Clone, Eq, PartialEq)]
112pub enum DecoderStatus {
113 /// The decoder needs more data to complete decoding.
114 ///
115 /// Continue pushing byte slices with [`Decoder::push_bytes`] until this status changes to
116 /// [`Ready`](DecoderStatus::Ready).
117 NeedsMore,
118
119 /// The decoder has accumulated sufficient data and is ready to finalize.
120 ///
121 /// Call [`Decoder::end`] to complete the decoding process and obtain the final result.
122 Ready,
123}
124
125impl DecoderStatus {
126 /// Returns `true` if the decoder needs more data to continue.
127 pub fn needs_more(&self) -> bool { matches!(self, Self::NeedsMore) }
128
129 /// Returns `true` if ready to produce decoded value with [`Decoder::end`].
130 pub fn is_ready(&self) -> bool { matches!(self, Self::Ready) }
131}
132
133/// Decodes an object from a byte slice.
134///
135/// # Errors
136///
137/// Returns an error if the decoder encounters an error while parsing the data, including
138/// insufficient data. This function also errors if the provided slice is not completely consumed
139/// during decode.
140pub fn decode_from_slice<T: Decode>(
141 bytes: &[u8],
142) -> Result<T, DecodeError<<T::Decoder as Decoder>::Error>> {
143 let mut remaining = bytes;
144 let data = decode_from_slice_unbounded::<T>(&mut remaining).map_err(DecodeError::Parse)?;
145
146 if remaining.is_empty() {
147 Ok(data)
148 } else {
149 Err(DecodeError::Unconsumed(UnconsumedError()))
150 }
151}
152
153/// Decodes an object from an unbounded byte slice.
154///
155/// Unlike [`decode_from_slice`], this function will not error if the slice contains additional
156/// bytes that are not required to decode. Furthermore, the byte slice reference provided to this
157/// function will be updated based on the consumed data, returning the unconsumed bytes.
158///
159/// # Errors
160///
161/// Returns an error if the decoder encounters an error while parsing the data, including
162/// insufficient data.
163pub fn decode_from_slice_unbounded<T>(
164 bytes: &mut &[u8],
165) -> Result<T, <T::Decoder as Decoder>::Error>
166where
167 T: Decode,
168{
169 let mut decoder = T::decoder();
170
171 while !bytes.is_empty() {
172 if decoder.push_bytes(bytes)?.is_ready() {
173 break;
174 }
175 }
176
177 decoder.end()
178}
179
180/// Decodes an object from a buffered reader.
181///
182/// # Performance
183///
184/// For unbuffered readers (like [`std::fs::File`] or [`std::net::TcpStream`]), consider wrapping
185/// your reader with [`std::io::BufReader`] in order to use this function. This avoids frequent
186/// small reads, which can significantly impact performance.
187///
188/// # Errors
189///
190/// Returns [`ReadError::Decode`] if the decoder encounters an error while parsing the data, or
191/// [`ReadError::Io`] if an I/O error occurs while reading.
192#[cfg(feature = "std")]
193pub fn decode_from_read<T, R>(mut reader: R) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
194where
195 T: Decode,
196 R: std::io::BufRead,
197{
198 let mut decoder = T::decoder();
199
200 loop {
201 let mut buffer = match reader.fill_buf() {
202 Ok(buffer) => buffer,
203 // Auto retry read for non-fatal error.
204 Err(error) if error.kind() == std::io::ErrorKind::Interrupted => continue,
205 Err(error) => return Err(ReadError::Io(error)),
206 };
207
208 if buffer.is_empty() {
209 // EOF, but still try to finalize the decoder.
210 return decoder.end().map_err(ReadError::Decode);
211 }
212
213 let original_len = buffer.len();
214 let status = decoder.push_bytes(&mut buffer).map_err(ReadError::Decode)?;
215 let consumed = original_len - buffer.len();
216 reader.consume(consumed);
217
218 if status.is_ready() {
219 return decoder.end().map_err(ReadError::Decode);
220 }
221 }
222}
223
224/// Decodes an object from an unbuffered reader using a fixed-size buffer.
225///
226/// For most use cases, prefer [`decode_from_read`] with a [`std::io::BufReader`]. This function is
227/// only needed when you have an unbuffered reader which you cannot wrap. It will probably have
228/// worse performance.
229///
230/// # Buffer
231///
232/// Uses a fixed 4KB (4096 bytes) stack-allocated buffer that is reused across read operations. This
233/// size is a good balance between memory usage and system call efficiency for most use cases.
234///
235/// For different buffer sizes, use [`decode_from_read_unbuffered_with`].
236///
237/// # Errors
238///
239/// Returns [`ReadError::Decode`] if the decoder encounters an error while parsing the data, or
240/// [`ReadError::Io`] if an I/O error occurs while reading.
241#[cfg(feature = "std")]
242pub fn decode_from_read_unbuffered<T, R>(
243 reader: R,
244) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
245where
246 T: Decode,
247 R: std::io::Read,
248{
249 decode_from_read_unbuffered_with::<T, R, 4096>(reader)
250}
251
252/// Decodes an object from an unbuffered reader using a custom-sized buffer.
253///
254/// For most use cases, prefer [`decode_from_read`] with a [`std::io::BufReader`]. This function is
255/// only needed when you have an unbuffered reader which you cannot wrap. It will probably have
256/// worse performance.
257///
258/// # Buffer
259///
260/// The `BUFFER_SIZE` parameter controls the intermediate buffer size used for reading. The buffer
261/// is allocated on the stack (not heap) and reused across read operations. Larger buffers reduce
262/// the number of system calls, but use more memory.
263///
264/// # Errors
265///
266/// Returns [`ReadError::Decode`] if the decoder encounters an error while parsing the data, or
267/// [`ReadError::Io`] if an I/O error occurs while reading.
268#[cfg(feature = "std")]
269pub fn decode_from_read_unbuffered_with<T, R, const BUFFER_SIZE: usize>(
270 mut reader: R,
271) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
272where
273 T: Decode,
274 R: std::io::Read,
275{
276 let mut decoder = T::decoder();
277 let mut buffer = [0u8; BUFFER_SIZE];
278
279 while decoder.read_limit() > 0 {
280 // Only read what we need, up to buffer size.
281 let clamped_buffer = &mut buffer[..decoder.read_limit().min(BUFFER_SIZE)];
282 match reader.read(clamped_buffer) {
283 Ok(0) => {
284 // EOF, but still try to finalize the decoder.
285 return decoder.end().map_err(ReadError::Decode);
286 }
287 Ok(bytes_read) => {
288 if decoder
289 .push_bytes(&mut &clamped_buffer[..bytes_read])
290 .map_err(ReadError::Decode)?
291 .is_ready()
292 {
293 return decoder.end().map_err(ReadError::Decode);
294 }
295 }
296 Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {
297 // Auto retry read for non-fatal error.
298 }
299 Err(e) => return Err(ReadError::Io(e)),
300 }
301 }
302
303 decoder.end().map_err(ReadError::Decode)
304}
305
306/// Checks that the given bytes decode to the expected value, panicking if they don't.
307///
308/// This is intended for tests only.
309///
310/// # Panics
311///
312/// If the decoded value doesn't match the expected value, or if decoding fails.
313#[track_caller]
314pub fn check_decode<T: Decode + Eq + core::fmt::Debug>(bytes: &[u8], expected: &T)
315where
316 <T::Decoder as Decoder>::Error: core::fmt::Debug,
317{
318 let decoder = T::decoder();
319 check_decoder(decoder, bytes, expected);
320}
321
322/// Checks that the given `decoder` produces the expected value, panicking if it doesn't.
323///
324/// This is intended for tests only.
325///
326/// # Panics
327///
328/// If the decoder doesn't produce the expected value or if decoding fails.
329#[track_caller]
330pub fn check_decoder<D: Decoder>(mut decoder: D, mut bytes: &[u8], expected: &D::Output)
331where
332 D::Output: Eq + core::fmt::Debug,
333 D::Error: core::fmt::Debug,
334{
335 loop {
336 match decoder.push_bytes(&mut bytes) {
337 Ok(status) => {
338 if status.is_ready() {
339 break;
340 }
341 assert!(!bytes.is_empty(), "decoder needs more data but no bytes remaining");
342 }
343 Err(e) => panic!("decoder failed with error: {e:?}"),
344 }
345 }
346
347 match decoder.end() {
348 Ok(result) => {
349 assert_eq!(&result, expected, "decoded value doesn't match expected value");
350 }
351 Err(e) => panic!("decoder finalization failed with error: {e:?}"),
352 }
353}