Skip to content

Commit c6ce97e

Browse files
committed
units: Wrap decoder error types
If two encoders return the same error it is not currently possible to compose them with our decoders. Having a new type instead of returning the `UnexpectedEofError` makes this possible (assuming one doesn't want to compose two decoders of the same type).
1 parent 11811e0 commit c6ce97e

File tree

5 files changed

+119
-12
lines changed

5 files changed

+119
-12
lines changed

units/src/block.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@
1111
//! The difference between these types and the locktime types is that these types are thin wrappers
1212
//! whereas the locktime types contain more complex locktime specific abstractions.
1313
14+
#[cfg(feature = "encoding")]
15+
use core::convert::Infallible;
1416
use core::{fmt, ops};
1517

1618
#[cfg(feature = "arbitrary")]
1719
use arbitrary::{Arbitrary, Unstructured};
20+
#[cfg(feature = "encoding")]
21+
use internals::write_err;
1822
#[cfg(feature = "serde")]
1923
use serde::{Deserialize, Deserializer, Serialize, Serializer};
2024

@@ -164,16 +168,16 @@ pub struct BlockHeightDecoder(encoding::ArrayDecoder<4>);
164168
#[cfg(feature = "encoding")]
165169
impl encoding::Decoder for BlockHeightDecoder {
166170
type Output = BlockHeight;
167-
type Error = encoding::UnexpectedEofError;
171+
type Error = BlockHeightDecoderError;
168172

169173
#[inline]
170174
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
171-
self.0.push_bytes(bytes)
175+
self.0.push_bytes(bytes).map_err(BlockHeightDecoderError)
172176
}
173177

174178
#[inline]
175179
fn end(self) -> Result<Self::Output, Self::Error> {
176-
let n = u32::from_le_bytes(self.0.end()?);
180+
let n = u32::from_le_bytes(self.0.end().map_err(BlockHeightDecoderError)?);
177181
Ok(BlockHeight::from_u32(n))
178182
}
179183
}
@@ -184,6 +188,28 @@ impl encoding::Decodable for BlockHeight {
184188
fn decoder() -> Self::Decoder { BlockHeightDecoder(encoding::ArrayDecoder::<4>::new()) }
185189
}
186190

191+
/// An error consensus decoding an `BlockHeight`.
192+
#[cfg(feature = "encoding")]
193+
#[derive(Debug, Clone, PartialEq, Eq)]
194+
pub struct BlockHeightDecoderError(encoding::UnexpectedEofError);
195+
196+
#[cfg(feature = "encoding")]
197+
impl From<Infallible> for BlockHeightDecoderError {
198+
fn from(never: Infallible) -> Self { match never {} }
199+
}
200+
201+
#[cfg(feature = "encoding")]
202+
impl fmt::Display for BlockHeightDecoderError {
203+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204+
write_err!(f, "block height decoder error"; self.0)
205+
}
206+
}
207+
208+
#[cfg(all(feature = "std", feature = "encoding"))]
209+
impl std::error::Error for BlockHeightDecoderError {
210+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
211+
}
212+
187213
impl_u32_wrapper! {
188214
/// An unsigned block interval.
189215
///

units/src/locktime/absolute/error.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,34 @@ use core::convert::Infallible;
66
use core::fmt;
77

88
use internals::error::InputString;
9+
#[cfg(feature = "encoding")]
10+
use internals::write_err;
911

1012
use super::{Height, MedianTimePast, LOCK_TIME_THRESHOLD};
1113
use crate::parse_int::ParseIntError;
1214

15+
/// An error consensus decoding an `LockTime`.
16+
#[cfg(feature = "encoding")]
17+
#[derive(Debug, Clone, PartialEq, Eq)]
18+
pub struct LockTimeDecoderError(pub(super) encoding::UnexpectedEofError);
19+
20+
#[cfg(feature = "encoding")]
21+
impl From<Infallible> for LockTimeDecoderError {
22+
fn from(never: Infallible) -> Self { match never {} }
23+
}
24+
25+
#[cfg(feature = "encoding")]
26+
impl fmt::Display for LockTimeDecoderError {
27+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28+
write_err!(f, "lock time decoder error"; self.0)
29+
}
30+
}
31+
32+
#[cfg(all(feature = "std", feature = "encoding"))]
33+
impl std::error::Error for LockTimeDecoderError {
34+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
35+
}
36+
1337
/// Tried to satisfy a lock-by-time lock using a height value.
1438
#[derive(Debug, Clone, PartialEq, Eq)]
1539
pub struct IncompatibleHeightError {

units/src/locktime/absolute/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use crate::parse_int::{self, PrefixedHexError, UnprefixedHexError};
2424
pub use self::error::{
2525
ConversionError, IncompatibleHeightError, IncompatibleTimeError, ParseHeightError, ParseTimeError,
2626
};
27+
#[cfg(feature = "encoding")]
28+
pub use self::error::LockTimeDecoderError;
2729

2830
/// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]).
2931
///
@@ -424,16 +426,16 @@ pub struct LockTimeDecoder(encoding::ArrayDecoder<4>);
424426
#[cfg(feature = "encoding")]
425427
impl encoding::Decoder for LockTimeDecoder {
426428
type Output = LockTime;
427-
type Error = encoding::UnexpectedEofError;
429+
type Error = LockTimeDecoderError;
428430

429431
#[inline]
430432
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
431-
self.0.push_bytes(bytes)
433+
Ok(self.0.push_bytes(bytes).map_err(LockTimeDecoderError)?)
432434
}
433435

434436
#[inline]
435437
fn end(self) -> Result<Self::Output, Self::Error> {
436-
let n = u32::from_le_bytes(self.0.end()?);
438+
let n = u32::from_le_bytes(self.0.end().map_err(LockTimeDecoderError)?);
437439
Ok(LockTime::from_consensus(n))
438440
}
439441
}

units/src/sequence.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@
1414
//! [BIP-0068]: <https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki>
1515
//! [BIP-0125]: <https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki>
1616
17+
#[cfg(feature = "encoding")]
18+
use core::convert::Infallible;
1719
use core::fmt;
1820

1921
#[cfg(feature = "arbitrary")]
2022
use arbitrary::{Arbitrary, Unstructured};
23+
#[cfg(feature = "encoding")]
24+
use internals::write_err;
2125
#[cfg(feature = "serde")]
2226
use serde::{Deserialize, Serialize};
2327

@@ -287,16 +291,16 @@ pub struct SequenceDecoder(encoding::ArrayDecoder<4>);
287291
#[cfg(feature = "encoding")]
288292
impl encoding::Decoder for SequenceDecoder {
289293
type Output = Sequence;
290-
type Error = encoding::UnexpectedEofError;
294+
type Error = SequenceDecoderError;
291295

292296
#[inline]
293297
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
294-
self.0.push_bytes(bytes)
298+
self.0.push_bytes(bytes).map_err(SequenceDecoderError)
295299
}
296300

297301
#[inline]
298302
fn end(self) -> Result<Self::Output, Self::Error> {
299-
let n = u32::from_le_bytes(self.0.end()?);
303+
let n = u32::from_le_bytes(self.0.end().map_err(SequenceDecoderError)?);
300304
Ok(Sequence::from_consensus(n))
301305
}
302306
}
@@ -307,6 +311,28 @@ impl encoding::Decodable for Sequence {
307311
fn decoder() -> Self::Decoder { SequenceDecoder(encoding::ArrayDecoder::<4>::new()) }
308312
}
309313

314+
/// An error consensus decoding an `Sequence`.
315+
#[cfg(feature = "encoding")]
316+
#[derive(Debug, Clone, PartialEq, Eq)]
317+
pub struct SequenceDecoderError(encoding::UnexpectedEofError);
318+
319+
#[cfg(feature = "encoding")]
320+
impl From<Infallible> for SequenceDecoderError {
321+
fn from(never: Infallible) -> Self { match never {} }
322+
}
323+
324+
#[cfg(feature = "encoding")]
325+
impl fmt::Display for SequenceDecoderError {
326+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
327+
write_err!(f, "sequence decoder error"; self.0)
328+
}
329+
}
330+
331+
#[cfg(all(feature = "std", feature = "encoding"))]
332+
impl std::error::Error for SequenceDecoderError {
333+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
334+
}
335+
310336
#[cfg(feature = "arbitrary")]
311337
#[cfg(feature = "alloc")]
312338
impl<'a> Arbitrary<'a> for Sequence {

units/src/time.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,15 @@
77
//! This differs from other UNIX timestamps in that we only use non-negative values. The Epoch
88
//! pre-dates Bitcoin so timestamps before this are not useful for block timestamps.
99
10+
#[cfg(feature = "encoding")]
11+
use core::convert::Infallible;
12+
#[cfg(feature = "encoding")]
13+
use core::fmt;
14+
1015
#[cfg(feature = "arbitrary")]
1116
use arbitrary::{Arbitrary, Unstructured};
17+
#[cfg(feature = "encoding")]
18+
use internals::write_err;
1219
#[cfg(feature = "serde")]
1320
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1421

@@ -94,16 +101,16 @@ pub struct BlockTimeDecoder(encoding::ArrayDecoder<4>);
94101
#[cfg(feature = "encoding")]
95102
impl encoding::Decoder for BlockTimeDecoder {
96103
type Output = BlockTime;
97-
type Error = encoding::UnexpectedEofError;
104+
type Error = BlockTimeDecoderError;
98105

99106
#[inline]
100107
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
101-
self.0.push_bytes(bytes)
108+
self.0.push_bytes(bytes).map_err(BlockTimeDecoderError)
102109
}
103110

104111
#[inline]
105112
fn end(self) -> Result<Self::Output, Self::Error> {
106-
let t = u32::from_le_bytes(self.0.end()?);
113+
let t = u32::from_le_bytes(self.0.end().map_err(BlockTimeDecoderError)?);
107114
Ok(BlockTime::from_u32(t))
108115
}
109116
}
@@ -114,6 +121,28 @@ impl encoding::Decodable for BlockTime {
114121
fn decoder() -> Self::Decoder { BlockTimeDecoder(encoding::ArrayDecoder::<4>::new()) }
115122
}
116123

124+
/// An error consensus decoding an `BlockTime`.
125+
#[cfg(feature = "encoding")]
126+
#[derive(Debug, Clone, PartialEq, Eq)]
127+
pub struct BlockTimeDecoderError(encoding::UnexpectedEofError);
128+
129+
#[cfg(feature = "encoding")]
130+
impl From<Infallible> for BlockTimeDecoderError {
131+
fn from(never: Infallible) -> Self { match never {} }
132+
}
133+
134+
#[cfg(feature = "encoding")]
135+
impl fmt::Display for BlockTimeDecoderError {
136+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137+
write_err!(f, "block time decoder error"; self.0)
138+
}
139+
}
140+
141+
#[cfg(all(feature = "std", feature = "encoding"))]
142+
impl std::error::Error for BlockTimeDecoderError {
143+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
144+
}
145+
117146
#[cfg(feature = "arbitrary")]
118147
impl<'a> Arbitrary<'a> for BlockTime {
119148
#[inline]

0 commit comments

Comments
 (0)