Skip to content

Commit 88c6c3b

Browse files
tchardingnyonson
authored andcommitted
units: Implement decoding traits
In a similar fashion to what we did for encoding; for each of the types that implements encoding add logic for decoding.
1 parent e36cc96 commit 88c6c3b

File tree

7 files changed

+184
-2
lines changed

7 files changed

+184
-2
lines changed

units/src/amount/error.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ impl fmt::Display for ParseAmountError {
137137
E::TooPrecise(ref error) => write_err!(f, "amount has a too high precision"; error),
138138
E::MissingDigits(ref error) => write_err!(f, "the input has too few digits"; error),
139139
E::InputTooLarge(ref error) => write_err!(f, "the input is too large"; error),
140-
E::InvalidCharacter(ref error) =>
141-
write_err!(f, "invalid character in the input"; error),
140+
E::InvalidCharacter(ref error) => {
141+
write_err!(f, "invalid character in the input"; error)
142+
}
142143
}
143144
}
144145
}
@@ -389,3 +390,44 @@ impl fmt::Display for PossiblyConfusingDenominationError {
389390
impl std::error::Error for PossiblyConfusingDenominationError {
390391
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
391392
}
393+
394+
/// An error consensus decoding an `Amount`.
395+
#[cfg(feature = "encoding")]
396+
#[derive(Debug, Clone, PartialEq, Eq)]
397+
#[non_exhaustive]
398+
pub enum AmountDecoderError {
399+
/// Not enough bytes given to decoder.
400+
UnexpectedEof(encoding::UnexpectedEofError),
401+
/// Decoded amount is too big.
402+
OutOfRange(OutOfRangeError),
403+
}
404+
405+
#[cfg(feature = "encoding")]
406+
impl From<Infallible> for AmountDecoderError {
407+
fn from(never: Infallible) -> Self { match never {} }
408+
}
409+
410+
#[cfg(feature = "encoding")]
411+
impl From<encoding::UnexpectedEofError> for AmountDecoderError {
412+
fn from(e: encoding::UnexpectedEofError) -> Self { Self::UnexpectedEof(e) }
413+
}
414+
415+
#[cfg(feature = "encoding")]
416+
impl fmt::Display for AmountDecoderError {
417+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
418+
match *self {
419+
Self::UnexpectedEof(ref e) => write_err!(f, "decode error"; e),
420+
Self::OutOfRange(ref e) => write_err!(f, "decode error"; e),
421+
}
422+
}
423+
}
424+
425+
#[cfg(all(feature = "std", feature = "encoding"))]
426+
impl std::error::Error for AmountDecoderError {
427+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
428+
match *self {
429+
Self::UnexpectedEof(ref e) => Some(e),
430+
Self::OutOfRange(ref e) => Some(e),
431+
}
432+
}
433+
}

units/src/amount/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ pub use self::{
3737
signed::SignedAmount,
3838
unsigned::Amount,
3939
};
40+
#[cfg(feature = "encoding")]
41+
#[doc(no_inline)]
42+
pub use self::error::AmountDecoderError;
4043
#[doc(no_inline)]
4144
pub use self::error::{OutOfRangeError, ParseAmountError, ParseDenominationError, ParseError};
4245

units/src/amount/unsigned.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use arbitrary::{Arbitrary, Unstructured};
1212
use internals::const_casts;
1313
use NumOpResult as R;
1414

15+
#[cfg(feature = "encoding")]
16+
use super::error::AmountDecoderError;
1517
use super::error::{ParseAmountErrorInner, ParseErrorInner};
1618
use super::{
1719
parse_signed_to_satoshi, split_amount_and_denomination, Denomination, Display, DisplayStyle,
@@ -576,6 +578,33 @@ impl encoding::Encodable for Amount {
576578
}
577579
}
578580

581+
/// The decoder for the [`Amount`] type.
582+
#[cfg(feature = "encoding")]
583+
pub struct AmountDecoder(encoding::ArrayDecoder<8>);
584+
585+
#[cfg(feature = "encoding")]
586+
impl encoding::Decoder for AmountDecoder {
587+
type Output = Amount;
588+
type Error = AmountDecoderError;
589+
590+
#[inline]
591+
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
592+
Ok(self.0.push_bytes(bytes)?)
593+
}
594+
595+
#[inline]
596+
fn end(self) -> Result<Self::Output, Self::Error> {
597+
let a = u64::from_le_bytes(self.0.end()?);
598+
Ok(Amount::from_sat(a).map_err(AmountDecoderError::OutOfRange)?)
599+
}
600+
}
601+
602+
#[cfg(feature = "encoding")]
603+
impl encoding::Decodable for Amount {
604+
type Decoder = AmountDecoder;
605+
fn decoder() -> Self::Decoder { AmountDecoder(encoding::ArrayDecoder::<8>::new()) }
606+
}
607+
579608
#[cfg(feature = "arbitrary")]
580609
impl<'a> Arbitrary<'a> for Amount {
581610
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {

units/src/block.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,33 @@ impl encoding::Encodable for BlockHeight {
157157
}
158158
}
159159

160+
/// The decoder for the [`BlockHeight`] type.
161+
#[cfg(feature = "encoding")]
162+
pub struct BlockHeightDecoder(encoding::ArrayDecoder<4>);
163+
164+
#[cfg(feature = "encoding")]
165+
impl encoding::Decoder for BlockHeightDecoder {
166+
type Output = BlockHeight;
167+
type Error = encoding::UnexpectedEofError;
168+
169+
#[inline]
170+
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
171+
self.0.push_bytes(bytes)
172+
}
173+
174+
#[inline]
175+
fn end(self) -> Result<Self::Output, Self::Error> {
176+
let n = u32::from_le_bytes(self.0.end()?);
177+
Ok(BlockHeight::from_u32(n))
178+
}
179+
}
180+
181+
#[cfg(feature = "encoding")]
182+
impl encoding::Decodable for BlockHeight {
183+
type Decoder = BlockHeightDecoder;
184+
fn decoder() -> Self::Decoder { BlockHeightDecoder(encoding::ArrayDecoder::<4>::new()) }
185+
}
186+
160187
impl_u32_wrapper! {
161188
/// An unsigned block interval.
162189
///

units/src/locktime/absolute/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,33 @@ impl encoding::Encodable for LockTime {
417417
}
418418
}
419419

420+
/// The decoder for the [`LockTime`] type.
421+
#[cfg(feature = "encoding")]
422+
pub struct LockTimeDecoder(encoding::ArrayDecoder<4>);
423+
424+
#[cfg(feature = "encoding")]
425+
impl encoding::Decoder for LockTimeDecoder {
426+
type Output = LockTime;
427+
type Error = encoding::UnexpectedEofError;
428+
429+
#[inline]
430+
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
431+
self.0.push_bytes(bytes)
432+
}
433+
434+
#[inline]
435+
fn end(self) -> Result<Self::Output, Self::Error> {
436+
let n = u32::from_le_bytes(self.0.end()?);
437+
Ok(LockTime::from_consensus(n))
438+
}
439+
}
440+
441+
#[cfg(feature = "encoding")]
442+
impl encoding::Decodable for LockTime {
443+
type Decoder = LockTimeDecoder;
444+
fn decoder() -> Self::Decoder { LockTimeDecoder(encoding::ArrayDecoder::<4>::new()) }
445+
}
446+
420447
impl From<Height> for LockTime {
421448
#[inline]
422449
fn from(h: Height) -> Self { LockTime::Blocks(h) }

units/src/sequence.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,33 @@ impl encoding::Encodable for Sequence {
280280
}
281281
}
282282

283+
/// The decoder for the [`Sequence`] type.
284+
#[cfg(feature = "encoding")]
285+
pub struct SequenceDecoder(encoding::ArrayDecoder<4>);
286+
287+
#[cfg(feature = "encoding")]
288+
impl encoding::Decoder for SequenceDecoder {
289+
type Output = Sequence;
290+
type Error = encoding::UnexpectedEofError;
291+
292+
#[inline]
293+
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
294+
self.0.push_bytes(bytes)
295+
}
296+
297+
#[inline]
298+
fn end(self) -> Result<Self::Output, Self::Error> {
299+
let n = u32::from_le_bytes(self.0.end()?);
300+
Ok(Sequence::from_consensus(n))
301+
}
302+
}
303+
304+
#[cfg(feature = "encoding")]
305+
impl encoding::Decodable for Sequence {
306+
type Decoder = SequenceDecoder;
307+
fn decoder() -> Self::Decoder { SequenceDecoder(encoding::ArrayDecoder::<4>::new()) }
308+
}
309+
283310
#[cfg(feature = "arbitrary")]
284311
#[cfg(feature = "alloc")]
285312
impl<'a> Arbitrary<'a> for Sequence {

units/src/time.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,33 @@ impl encoding::Encodable for BlockTime {
8787
}
8888
}
8989

90+
/// The decoder for the [`BlockTime`] type.
91+
#[cfg(feature = "encoding")]
92+
pub struct BlockTimeDecoder(encoding::ArrayDecoder<4>);
93+
94+
#[cfg(feature = "encoding")]
95+
impl encoding::Decoder for BlockTimeDecoder {
96+
type Output = BlockTime;
97+
type Error = encoding::UnexpectedEofError;
98+
99+
#[inline]
100+
fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
101+
self.0.push_bytes(bytes)
102+
}
103+
104+
#[inline]
105+
fn end(self) -> Result<Self::Output, Self::Error> {
106+
let t = u32::from_le_bytes(self.0.end()?);
107+
Ok(BlockTime::from_u32(t))
108+
}
109+
}
110+
111+
#[cfg(feature = "encoding")]
112+
impl encoding::Decodable for BlockTime {
113+
type Decoder = BlockTimeDecoder;
114+
fn decoder() -> Self::Decoder { BlockTimeDecoder(encoding::ArrayDecoder::<4>::new()) }
115+
}
116+
90117
#[cfg(feature = "arbitrary")]
91118
impl<'a> Arbitrary<'a> for BlockTime {
92119
#[inline]

0 commit comments

Comments
 (0)