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, Decodable, Decoder, ArrayDecoder, UnexpectedEofError};
20///
21/// struct Foo([u8; 4]);
22///
23/// struct FooDecoder(ArrayDecoder<4>);
24///
25/// impl Decoder for FooDecoder {
26/// type Output = Foo;
27/// type Error = UnexpectedEofError;
28///
29/// fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
30/// self.0.push_bytes(bytes)
31/// }
32/// fn end(self) -> Result<Self::Output, Self::Error> { self.0.end().map(Foo) }
33/// fn read_limit(&self) -> usize { self.0.read_limit() }
34/// }
35///
36/// impl Decodable for Foo {
37/// type Decoder = FooDecoder;
38/// fn decoder() -> Self::Decoder { FooDecoder(ArrayDecoder::new()) }
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 Decodable {
45 /// Associated decoder for the type.
46 type Decoder: Decoder<Output = Self>;
47
48 /// Constructs a "default decoder" for the type.
49 fn decoder() -> Self::Decoder;
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 `Ok(true)`
62 /// if more bytes are needed to complete decoding, `Ok(false)` if the decoder is ready to
63 /// finalize with [`Self::end`], or `Err(error)` if parsing failed.
64 ///
65 /// # Errors
66 ///
67 /// Returns an error if the provided bytes are invalid or malformed according to the decoder's
68 /// validation rules. Insufficient data (needing more bytes) is *not* an error for this method,
69 /// the decoder will simply consume what it can and return `true` to indicate more data is
70 /// needed.
71 ///
72 /// # Panics
73 ///
74 /// May panic if called after a previous call to [`Self::push_bytes`] errored.
75 #[must_use = "must check result to avoid panics on subsequent calls"]
76 #[track_caller]
77 fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error>;
78
79 /// Completes the decoding process and return the final result.
80 ///
81 /// This consumes the decoder and should be called when no more input data is available.
82 ///
83 /// # Errors
84 ///
85 /// Returns an error if the decoder has not received sufficient data to complete decoding, or if
86 /// the accumulated data is invalid when considered as a complete object.
87 ///
88 /// # Panics
89 ///
90 /// May panic if called after a previous call to [`Self::push_bytes`] errored.
91 #[must_use = "must check result to avoid panics on subsequent calls"]
92 #[track_caller]
93 fn end(self) -> Result<Self::Output, Self::Error>;
94
95 /// Returns the maximum number of bytes this decoder can consume without over-reading.
96 ///
97 /// Returns 0 if the decoder is complete and ready to finalize with [`Self::end`]. This is used
98 /// by [`decode_from_read_unbuffered`] to optimize read sizes, avoiding both inefficient
99 /// under-reads and unnecessary over-reads.
100 fn read_limit(&self) -> usize;
101}
102
103/// Decodes an object from a byte slice.
104///
105/// # Errors
106///
107/// Returns an error if the decoder encounters an error while parsing the data, including
108/// insufficient data. This function also errors if the provided slice is not completely consumed
109/// during decode.
110pub fn decode_from_slice<T: Decodable>(
111 bytes: &[u8],
112) -> Result<T, DecodeError<<T::Decoder as Decoder>::Error>> {
113 let mut remaining = bytes;
114 let data = decode_from_slice_unbounded::<T>(&mut remaining).map_err(DecodeError::Parse)?;
115
116 if remaining.is_empty() {
117 Ok(data)
118 } else {
119 Err(DecodeError::Unconsumed(UnconsumedError()))
120 }
121}
122
123/// Decodes an object from an unbounded byte slice.
124///
125/// Unlike [`decode_from_slice`], this function will not error if the slice contains additional
126/// bytes that are not required to decode. Furthermore, the byte slice reference provided to this
127/// function will be updated based on the consumed data, returning the unconsumed bytes.
128///
129/// # Errors
130///
131/// Returns an error if the decoder encounters an error while parsing the data, including
132/// insufficient data.
133pub fn decode_from_slice_unbounded<T>(
134 bytes: &mut &[u8],
135) -> Result<T, <T::Decoder as Decoder>::Error>
136where
137 T: Decodable,
138{
139 let mut decoder = T::decoder();
140
141 while !bytes.is_empty() {
142 if !decoder.push_bytes(bytes)? {
143 break;
144 }
145 }
146
147 decoder.end()
148}
149
150/// Decodes an object from a buffered reader.
151///
152/// # Performance
153///
154/// For unbuffered readers (like [`std::fs::File`] or [`std::net::TcpStream`]), consider wrapping
155/// your reader with [`std::io::BufReader`] in order to use this function. This avoids frequent
156/// small reads, which can significantly impact performance.
157///
158/// # Errors
159///
160/// Returns [`ReadError::Decode`] if the decoder encounters an error while parsing the data, or
161/// [`ReadError::Io`] if an I/O error occurs while reading.
162#[cfg(feature = "std")]
163pub fn decode_from_read<T, R>(mut reader: R) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
164where
165 T: Decodable,
166 R: std::io::BufRead,
167{
168 let mut decoder = T::decoder();
169
170 loop {
171 let mut buffer = match reader.fill_buf() {
172 Ok(buffer) => buffer,
173 // Auto retry read for non-fatal error.
174 Err(error) if error.kind() == std::io::ErrorKind::Interrupted => continue,
175 Err(error) => return Err(ReadError::Io(error)),
176 };
177
178 if buffer.is_empty() {
179 // EOF, but still try to finalize the decoder.
180 return decoder.end().map_err(ReadError::Decode);
181 }
182
183 let original_len = buffer.len();
184 let need_more = decoder.push_bytes(&mut buffer).map_err(ReadError::Decode)?;
185 let consumed = original_len - buffer.len();
186 reader.consume(consumed);
187
188 if !need_more {
189 return decoder.end().map_err(ReadError::Decode);
190 }
191 }
192}
193
194/// Decodes an object from an unbuffered reader using a fixed-size buffer.
195///
196/// For most use cases, prefer [`decode_from_read`] with a [`std::io::BufReader`]. This function is
197/// only needed when you have an unbuffered reader which you cannot wrap. It will probably have
198/// worse performance.
199///
200/// # Buffer
201///
202/// Uses a fixed 4KB (4096 bytes) stack-allocated buffer that is reused across read operations. This
203/// size is a good balance between memory usage and system call efficiency for most use cases.
204///
205/// For different buffer sizes, use [`decode_from_read_unbuffered_with`].
206///
207/// # Errors
208///
209/// Returns [`ReadError::Decode`] if the decoder encounters an error while parsing the data, or
210/// [`ReadError::Io`] if an I/O error occurs while reading.
211#[cfg(feature = "std")]
212pub fn decode_from_read_unbuffered<T, R>(
213 reader: R,
214) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
215where
216 T: Decodable,
217 R: std::io::Read,
218{
219 decode_from_read_unbuffered_with::<T, R, 4096>(reader)
220}
221
222/// Decodes an object from an unbuffered reader using a custom-sized buffer.
223///
224/// For most use cases, prefer [`decode_from_read`] with a [`std::io::BufReader`]. This function is
225/// only needed when you have an unbuffered reader which you cannot wrap. It will probably have
226/// worse performance.
227///
228/// # Buffer
229///
230/// The `BUFFER_SIZE` parameter controls the intermediate buffer size used for reading. The buffer
231/// is allocated on the stack (not heap) and reused across read operations. Larger buffers reduce
232/// the number of system calls, but use more memory.
233///
234/// # Errors
235///
236/// Returns [`ReadError::Decode`] if the decoder encounters an error while parsing the data, or
237/// [`ReadError::Io`] if an I/O error occurs while reading.
238#[cfg(feature = "std")]
239pub fn decode_from_read_unbuffered_with<T, R, const BUFFER_SIZE: usize>(
240 mut reader: R,
241) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
242where
243 T: Decodable,
244 R: std::io::Read,
245{
246 let mut decoder = T::decoder();
247 let mut buffer = [0u8; BUFFER_SIZE];
248
249 while decoder.read_limit() > 0 {
250 // Only read what we need, up to buffer size.
251 let clamped_buffer = &mut buffer[..decoder.read_limit().min(BUFFER_SIZE)];
252 match reader.read(clamped_buffer) {
253 Ok(0) => {
254 // EOF, but still try to finalize the decoder.
255 return decoder.end().map_err(ReadError::Decode);
256 }
257 Ok(bytes_read) => {
258 if !decoder
259 .push_bytes(&mut &clamped_buffer[..bytes_read])
260 .map_err(ReadError::Decode)?
261 {
262 return decoder.end().map_err(ReadError::Decode);
263 }
264 }
265 Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {
266 // Auto retry read for non-fatal error.
267 }
268 Err(e) => return Err(ReadError::Io(e)),
269 }
270 }
271
272 decoder.end().map_err(ReadError::Decode)
273}