Skip to content

Commit 58b087d

Browse files
committed
Merge rust-bitcoin#3674: Close amounts error types
fd2a5c1 Close amounts error types (Tobin C. Harding) 23c7727 Reduce code comment lines (Tobin C. Harding) d595f42 Remove whitespace between enum variants (Tobin C. Harding) Pull request description: Close the two pubic enum error types in `units::amounts`. All the other structs are closed already because they either have private fields or marked `non_exhaustive`. ACKs for top commit: apoelstra: ACK fd2a5c1; successfully ran local tests; thanks! Tree-SHA512: f8d68ef821449e0829c926cf527df4b226b29c8d1d41b320a016fbf70b4b39cc54c8c218955caa0c3776158eeeae0ebacc1cc89dab67bafc399b94063324ab0e
2 parents 7ba24e9 + fd2a5c1 commit 58b087d

File tree

5 files changed

+69
-53
lines changed

5 files changed

+69
-53
lines changed

units/src/amount/error.rs

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,56 +11,56 @@ use super::INPUT_STRING_LEN_LIMIT;
1111

1212
/// An error during amount parsing amount with denomination.
1313
#[derive(Debug, Clone, PartialEq, Eq)]
14-
#[non_exhaustive]
15-
pub enum ParseError {
14+
pub struct ParseError(pub(crate) ParseErrorInner);
15+
16+
#[derive(Debug, Clone, PartialEq, Eq)]
17+
pub(crate) enum ParseErrorInner {
1618
/// Invalid amount.
1719
Amount(ParseAmountError),
18-
1920
/// Invalid denomination.
2021
Denomination(ParseDenominationError),
21-
2222
/// The denomination was not identified.
2323
MissingDenomination(MissingDenominationError),
2424
}
2525

2626
internals::impl_from_infallible!(ParseError);
27+
internals::impl_from_infallible!(ParseErrorInner);
2728

2829
impl From<ParseAmountError> for ParseError {
29-
fn from(e: ParseAmountError) -> Self { Self::Amount(e) }
30+
fn from(e: ParseAmountError) -> Self { Self(ParseErrorInner::Amount(e)) }
3031
}
3132

3233
impl From<ParseDenominationError> for ParseError {
33-
fn from(e: ParseDenominationError) -> Self { Self::Denomination(e) }
34+
fn from(e: ParseDenominationError) -> Self { Self(ParseErrorInner::Denomination(e)) }
3435
}
3536

3637
impl From<OutOfRangeError> for ParseError {
37-
fn from(e: OutOfRangeError) -> Self { Self::Amount(e.into()) }
38+
fn from(e: OutOfRangeError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
3839
}
3940

4041
impl From<TooPreciseError> for ParseError {
41-
fn from(e: TooPreciseError) -> Self { Self::Amount(e.into()) }
42+
fn from(e: TooPreciseError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
4243
}
4344

4445
impl From<MissingDigitsError> for ParseError {
45-
fn from(e: MissingDigitsError) -> Self { Self::Amount(e.into()) }
46+
fn from(e: MissingDigitsError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
4647
}
4748

4849
impl From<InputTooLargeError> for ParseError {
49-
fn from(e: InputTooLargeError) -> Self { Self::Amount(e.into()) }
50+
fn from(e: InputTooLargeError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
5051
}
5152

5253
impl From<InvalidCharacterError> for ParseError {
53-
fn from(e: InvalidCharacterError) -> Self { Self::Amount(e.into()) }
54+
fn from(e: InvalidCharacterError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
5455
}
5556

5657
impl fmt::Display for ParseError {
5758
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58-
match self {
59-
ParseError::Amount(error) => write_err!(f, "invalid amount"; error),
60-
ParseError::Denomination(error) => write_err!(f, "invalid denomination"; error),
61-
// We consider this to not be a source because it currently doesn't contain useful
62-
// information
63-
ParseError::MissingDenomination(_) =>
59+
match self.0 {
60+
ParseErrorInner::Amount(ref e) => write_err!(f, "invalid amount"; e),
61+
ParseErrorInner::Denomination(ref e) => write_err!(f, "invalid denomination"; e),
62+
// We consider this to not be a source because it currently doesn't contain useful info.
63+
ParseErrorInner::MissingDenomination(_) =>
6464
f.write_str("the input doesn't contain a denomination"),
6565
}
6666
}
@@ -69,20 +69,21 @@ impl fmt::Display for ParseError {
6969
#[cfg(feature = "std")]
7070
impl std::error::Error for ParseError {
7171
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
72-
match self {
73-
ParseError::Amount(error) => Some(error),
74-
ParseError::Denomination(error) => Some(error),
75-
// We consider this to not be a source because it currently doesn't contain useful
76-
// information
77-
ParseError::MissingDenomination(_) => None,
72+
match self.0 {
73+
ParseErrorInner::Amount(ref e) => Some(e),
74+
ParseErrorInner::Denomination(ref e) => Some(e),
75+
// We consider this to not be a source because it currently doesn't contain useful info.
76+
ParseErrorInner::MissingDenomination(_) => None,
7877
}
7978
}
8079
}
8180

8281
/// An error during amount parsing.
8382
#[derive(Debug, Clone, PartialEq, Eq)]
84-
#[non_exhaustive]
85-
pub enum ParseAmountError {
83+
pub struct ParseAmountError(pub(crate) ParseAmountErrorInner);
84+
85+
#[derive(Debug, Clone, PartialEq, Eq)]
86+
pub(crate) enum ParseAmountErrorInner {
8687
/// The amount is too big or too small.
8788
OutOfRange(OutOfRangeError),
8889
/// Amount has higher precision than supported by the type.
@@ -96,28 +97,31 @@ pub enum ParseAmountError {
9697
}
9798

9899
impl From<TooPreciseError> for ParseAmountError {
99-
fn from(value: TooPreciseError) -> Self { Self::TooPrecise(value) }
100+
fn from(value: TooPreciseError) -> Self { Self(ParseAmountErrorInner::TooPrecise(value)) }
100101
}
101102

102103
impl From<MissingDigitsError> for ParseAmountError {
103-
fn from(value: MissingDigitsError) -> Self { Self::MissingDigits(value) }
104+
fn from(value: MissingDigitsError) -> Self { Self(ParseAmountErrorInner::MissingDigits(value)) }
104105
}
105106

106107
impl From<InputTooLargeError> for ParseAmountError {
107-
fn from(value: InputTooLargeError) -> Self { Self::InputTooLarge(value) }
108+
fn from(value: InputTooLargeError) -> Self { Self(ParseAmountErrorInner::InputTooLarge(value)) }
108109
}
109110

110111
impl From<InvalidCharacterError> for ParseAmountError {
111-
fn from(value: InvalidCharacterError) -> Self { Self::InvalidCharacter(value) }
112+
fn from(value: InvalidCharacterError) -> Self {
113+
Self(ParseAmountErrorInner::InvalidCharacter(value))
114+
}
112115
}
113116

114117
internals::impl_from_infallible!(ParseAmountError);
118+
internals::impl_from_infallible!(ParseAmountErrorInner);
115119

116120
impl fmt::Display for ParseAmountError {
117121
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118-
use ParseAmountError::*;
122+
use ParseAmountErrorInner::*;
119123

120-
match *self {
124+
match self.0 {
121125
OutOfRange(ref error) => write_err!(f, "amount out of range"; error),
122126
TooPrecise(ref error) => write_err!(f, "amount has a too high precision"; error),
123127
MissingDigits(ref error) => write_err!(f, "the input has too few digits"; error),
@@ -130,9 +134,9 @@ impl fmt::Display for ParseAmountError {
130134
#[cfg(feature = "std")]
131135
impl std::error::Error for ParseAmountError {
132136
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
133-
use ParseAmountError::*;
137+
use ParseAmountErrorInner::*;
134138

135-
match *self {
139+
match self.0 {
136140
TooPrecise(ref error) => Some(error),
137141
InputTooLarge(ref error) => Some(error),
138142
OutOfRange(ref error) => Some(error),
@@ -199,7 +203,9 @@ impl fmt::Display for OutOfRangeError {
199203
impl std::error::Error for OutOfRangeError {}
200204

201205
impl From<OutOfRangeError> for ParseAmountError {
202-
fn from(value: OutOfRangeError) -> Self { ParseAmountError::OutOfRange(value) }
206+
fn from(value: OutOfRangeError) -> Self {
207+
ParseAmountError(ParseAmountErrorInner::OutOfRange(value))
208+
}
203209
}
204210

205211
/// Error returned when the input string has higher precision than satoshis.

units/src/amount/mod.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use core::cmp::Ordering;
2020
use core::fmt;
2121
use core::str::FromStr;
2222

23-
use self::error::MissingDigitsKind;
23+
use self::error::{MissingDigitsKind, ParseAmountErrorInner, ParseErrorInner};
2424

2525
#[rustfmt::skip] // Keep public re-exports separate.
2626
#[doc(inline)]
@@ -297,10 +297,12 @@ impl InnerParseError {
297297
match self {
298298
Self::Overflow { is_negative } =>
299299
OutOfRangeError { is_signed, is_greater_than_max: !is_negative }.into(),
300-
Self::TooPrecise(error) => ParseAmountError::TooPrecise(error),
301-
Self::MissingDigits(error) => ParseAmountError::MissingDigits(error),
302-
Self::InputTooLarge(len) => ParseAmountError::InputTooLarge(InputTooLargeError { len }),
303-
Self::InvalidCharacter(error) => ParseAmountError::InvalidCharacter(error),
300+
Self::TooPrecise(e) => ParseAmountError(ParseAmountErrorInner::TooPrecise(e)),
301+
Self::MissingDigits(e) => ParseAmountError(ParseAmountErrorInner::MissingDigits(e)),
302+
Self::InputTooLarge(len) =>
303+
ParseAmountError(ParseAmountErrorInner::InputTooLarge(InputTooLargeError { len })),
304+
Self::InvalidCharacter(e) =>
305+
ParseAmountError(ParseAmountErrorInner::InvalidCharacter(e)),
304306
}
305307
}
306308
}
@@ -311,7 +313,7 @@ fn split_amount_and_denomination(s: &str) -> Result<(&str, Denomination), ParseE
311313
} else {
312314
let i = s
313315
.find(|c: char| c.is_alphabetic())
314-
.ok_or(ParseError::MissingDenomination(MissingDenominationError))?;
316+
.ok_or(ParseError(ParseErrorInner::MissingDenomination(MissingDenominationError)))?;
315317
(i, i)
316318
};
317319
Ok((&s[..i], s[j..].parse()?))

units/src/amount/signed.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use core::{default, fmt, ops};
1010
#[cfg(feature = "arbitrary")]
1111
use arbitrary::{Arbitrary, Unstructured};
1212

13+
use super::error::{ParseAmountErrorInner, ParseErrorInner};
1314
use super::{
1415
parse_signed_to_satoshi, split_amount_and_denomination, Amount, Denomination, Display,
1516
DisplayStyle, OutOfRangeError, ParseAmountError, ParseError,
@@ -107,12 +108,14 @@ impl SignedAmount {
107108
pub fn from_str_in(s: &str, denom: Denomination) -> Result<SignedAmount, ParseAmountError> {
108109
match parse_signed_to_satoshi(s, denom).map_err(|error| error.convert(true))? {
109110
// (negative, amount)
110-
(false, sat) if sat > i64::MAX as u64 =>
111-
Err(ParseAmountError::OutOfRange(OutOfRangeError::too_big(true))),
111+
(false, sat) if sat > i64::MAX as u64 => Err(ParseAmountError(
112+
ParseAmountErrorInner::OutOfRange(OutOfRangeError::too_big(true)),
113+
)),
112114
(false, sat) => Ok(SignedAmount(sat as i64)),
113115
(true, sat) if sat == i64::MIN.unsigned_abs() => Ok(SignedAmount(i64::MIN)),
114-
(true, sat) if sat > i64::MIN.unsigned_abs() =>
115-
Err(ParseAmountError::OutOfRange(OutOfRangeError::too_small())),
116+
(true, sat) if sat > i64::MIN.unsigned_abs() => Err(ParseAmountError(
117+
ParseAmountErrorInner::OutOfRange(OutOfRangeError::too_small()),
118+
)),
116119
(true, sat) => Ok(SignedAmount(-(sat as i64))),
117120
}
118121
}
@@ -430,7 +433,7 @@ impl FromStr for SignedAmount {
430433
let result = SignedAmount::from_str_with_denomination(s);
431434

432435
match result {
433-
Err(ParseError::MissingDenomination(_)) => {
436+
Err(ParseError(ParseErrorInner::MissingDenomination(_))) => {
434437
let d = SignedAmount::from_str_in(s, Denomination::Satoshi);
435438

436439
if d == Ok(SignedAmount::ZERO) {

units/src/amount/tests.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ fn from_str_zero() {
3333
match s.parse::<Amount>() {
3434
Err(e) => assert_eq!(
3535
e,
36-
ParseError::Amount(ParseAmountError::OutOfRange(OutOfRangeError::negative()))
36+
ParseError(ParseErrorInner::Amount(ParseAmountError(
37+
ParseAmountErrorInner::OutOfRange(OutOfRangeError::negative())
38+
)))
3739
),
3840
Ok(_) => panic!("unsigned amount from {}", s),
3941
}
@@ -321,7 +323,7 @@ fn parsing() {
321323
// more than 50 chars.
322324
assert_eq!(
323325
p("100000000000000.00000000000000000000000000000000000", Denomination::Bitcoin),
324-
Err(E::InputTooLarge(InputTooLargeError { len: 51 }))
326+
Err(E(ParseAmountErrorInner::InputTooLarge(InputTooLargeError { len: 51 })))
325327
);
326328
}
327329

@@ -731,10 +733,10 @@ fn serde_as_btc() {
731733
// errors
732734
let t: Result<T, serde_json::Error> =
733735
serde_json::from_str("{\"amt\": 1000000.000000001, \"samt\": 1}");
734-
assert!(t
735-
.unwrap_err()
736-
.to_string()
737-
.contains(&ParseAmountError::TooPrecise(TooPreciseError { position: 16 }).to_string()));
736+
assert!(t.unwrap_err().to_string().contains(
737+
&ParseAmountError(ParseAmountErrorInner::TooPrecise(TooPreciseError { position: 16 }))
738+
.to_string()
739+
));
738740
let t: Result<T, serde_json::Error> = serde_json::from_str("{\"amt\": -1, \"samt\": 1}");
739741
assert!(t.unwrap_err().to_string().contains(&OutOfRangeError::negative().to_string()));
740742
}

units/src/amount/unsigned.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use core::{default, fmt, ops};
1010
#[cfg(feature = "arbitrary")]
1111
use arbitrary::{Arbitrary, Unstructured};
1212

13+
use super::error::{ParseAmountErrorInner, ParseErrorInner};
1314
use super::{
1415
parse_signed_to_satoshi, split_amount_and_denomination, Denomination, Display, DisplayStyle,
1516
OutOfRangeError, ParseAmountError, ParseError, SignedAmount,
@@ -115,7 +116,9 @@ impl Amount {
115116
let (negative, satoshi) =
116117
parse_signed_to_satoshi(s, denom).map_err(|error| error.convert(false))?;
117118
if negative {
118-
return Err(ParseAmountError::OutOfRange(OutOfRangeError::negative()));
119+
return Err(ParseAmountError(ParseAmountErrorInner::OutOfRange(
120+
OutOfRangeError::negative(),
121+
)));
119122
}
120123
Ok(Amount::from_sat(satoshi))
121124
}
@@ -417,7 +420,7 @@ impl FromStr for Amount {
417420
let result = Amount::from_str_with_denomination(s);
418421

419422
match result {
420-
Err(ParseError::MissingDenomination(_)) => {
423+
Err(ParseError(ParseErrorInner::MissingDenomination(_))) => {
421424
let d = Amount::from_str_in(s, Denomination::Satoshi);
422425

423426
if d == Ok(Amount::ZERO) {

0 commit comments

Comments
 (0)