Skip to content

Commit fd2a5c1

Browse files
committed
Close amounts error types
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`.
1 parent 23c7727 commit fd2a5c1

File tree

5 files changed

+67
-47
lines changed

5 files changed

+67
-47
lines changed

units/src/amount/error.rs

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ 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),
1820
/// Invalid denomination.
@@ -22,42 +24,43 @@ pub enum ParseError {
2224
}
2325

2426
internals::impl_from_infallible!(ParseError);
27+
internals::impl_from_infallible!(ParseErrorInner);
2528

2629
impl From<ParseAmountError> for ParseError {
27-
fn from(e: ParseAmountError) -> Self { Self::Amount(e) }
30+
fn from(e: ParseAmountError) -> Self { Self(ParseErrorInner::Amount(e)) }
2831
}
2932

3033
impl From<ParseDenominationError> for ParseError {
31-
fn from(e: ParseDenominationError) -> Self { Self::Denomination(e) }
34+
fn from(e: ParseDenominationError) -> Self { Self(ParseErrorInner::Denomination(e)) }
3235
}
3336

3437
impl From<OutOfRangeError> for ParseError {
35-
fn from(e: OutOfRangeError) -> Self { Self::Amount(e.into()) }
38+
fn from(e: OutOfRangeError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
3639
}
3740

3841
impl From<TooPreciseError> for ParseError {
39-
fn from(e: TooPreciseError) -> Self { Self::Amount(e.into()) }
42+
fn from(e: TooPreciseError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
4043
}
4144

4245
impl From<MissingDigitsError> for ParseError {
43-
fn from(e: MissingDigitsError) -> Self { Self::Amount(e.into()) }
46+
fn from(e: MissingDigitsError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
4447
}
4548

4649
impl From<InputTooLargeError> for ParseError {
47-
fn from(e: InputTooLargeError) -> Self { Self::Amount(e.into()) }
50+
fn from(e: InputTooLargeError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
4851
}
4952

5053
impl From<InvalidCharacterError> for ParseError {
51-
fn from(e: InvalidCharacterError) -> Self { Self::Amount(e.into()) }
54+
fn from(e: InvalidCharacterError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
5255
}
5356

5457
impl fmt::Display for ParseError {
5558
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56-
match self {
57-
ParseError::Amount(error) => write_err!(f, "invalid amount"; error),
58-
ParseError::Denomination(error) => write_err!(f, "invalid denomination"; error),
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),
5962
// We consider this to not be a source because it currently doesn't contain useful info.
60-
ParseError::MissingDenomination(_) =>
63+
ParseErrorInner::MissingDenomination(_) =>
6164
f.write_str("the input doesn't contain a denomination"),
6265
}
6366
}
@@ -66,19 +69,21 @@ impl fmt::Display for ParseError {
6669
#[cfg(feature = "std")]
6770
impl std::error::Error for ParseError {
6871
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
69-
match self {
70-
ParseError::Amount(error) => Some(error),
71-
ParseError::Denomination(error) => Some(error),
72+
match self.0 {
73+
ParseErrorInner::Amount(ref e) => Some(e),
74+
ParseErrorInner::Denomination(ref e) => Some(e),
7275
// We consider this to not be a source because it currently doesn't contain useful info.
73-
ParseError::MissingDenomination(_) => None,
76+
ParseErrorInner::MissingDenomination(_) => None,
7477
}
7578
}
7679
}
7780

7881
/// An error during amount parsing.
7982
#[derive(Debug, Clone, PartialEq, Eq)]
80-
#[non_exhaustive]
81-
pub enum ParseAmountError {
83+
pub struct ParseAmountError(pub(crate) ParseAmountErrorInner);
84+
85+
#[derive(Debug, Clone, PartialEq, Eq)]
86+
pub(crate) enum ParseAmountErrorInner {
8287
/// The amount is too big or too small.
8388
OutOfRange(OutOfRangeError),
8489
/// Amount has higher precision than supported by the type.
@@ -92,28 +97,31 @@ pub enum ParseAmountError {
9297
}
9398

9499
impl From<TooPreciseError> for ParseAmountError {
95-
fn from(value: TooPreciseError) -> Self { Self::TooPrecise(value) }
100+
fn from(value: TooPreciseError) -> Self { Self(ParseAmountErrorInner::TooPrecise(value)) }
96101
}
97102

98103
impl From<MissingDigitsError> for ParseAmountError {
99-
fn from(value: MissingDigitsError) -> Self { Self::MissingDigits(value) }
104+
fn from(value: MissingDigitsError) -> Self { Self(ParseAmountErrorInner::MissingDigits(value)) }
100105
}
101106

102107
impl From<InputTooLargeError> for ParseAmountError {
103-
fn from(value: InputTooLargeError) -> Self { Self::InputTooLarge(value) }
108+
fn from(value: InputTooLargeError) -> Self { Self(ParseAmountErrorInner::InputTooLarge(value)) }
104109
}
105110

106111
impl From<InvalidCharacterError> for ParseAmountError {
107-
fn from(value: InvalidCharacterError) -> Self { Self::InvalidCharacter(value) }
112+
fn from(value: InvalidCharacterError) -> Self {
113+
Self(ParseAmountErrorInner::InvalidCharacter(value))
114+
}
108115
}
109116

110117
internals::impl_from_infallible!(ParseAmountError);
118+
internals::impl_from_infallible!(ParseAmountErrorInner);
111119

112120
impl fmt::Display for ParseAmountError {
113121
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114-
use ParseAmountError::*;
122+
use ParseAmountErrorInner::*;
115123

116-
match *self {
124+
match self.0 {
117125
OutOfRange(ref error) => write_err!(f, "amount out of range"; error),
118126
TooPrecise(ref error) => write_err!(f, "amount has a too high precision"; error),
119127
MissingDigits(ref error) => write_err!(f, "the input has too few digits"; error),
@@ -126,9 +134,9 @@ impl fmt::Display for ParseAmountError {
126134
#[cfg(feature = "std")]
127135
impl std::error::Error for ParseAmountError {
128136
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
129-
use ParseAmountError::*;
137+
use ParseAmountErrorInner::*;
130138

131-
match *self {
139+
match self.0 {
132140
TooPrecise(ref error) => Some(error),
133141
InputTooLarge(ref error) => Some(error),
134142
OutOfRange(ref error) => Some(error),
@@ -195,7 +203,9 @@ impl fmt::Display for OutOfRangeError {
195203
impl std::error::Error for OutOfRangeError {}
196204

197205
impl From<OutOfRangeError> for ParseAmountError {
198-
fn from(value: OutOfRangeError) -> Self { ParseAmountError::OutOfRange(value) }
206+
fn from(value: OutOfRangeError) -> Self {
207+
ParseAmountError(ParseAmountErrorInner::OutOfRange(value))
208+
}
199209
}
200210

201211
/// 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,
@@ -92,12 +93,14 @@ impl SignedAmount {
9293
pub fn from_str_in(s: &str, denom: Denomination) -> Result<SignedAmount, ParseAmountError> {
9394
match parse_signed_to_satoshi(s, denom).map_err(|error| error.convert(true))? {
9495
// (negative, amount)
95-
(false, sat) if sat > i64::MAX as u64 =>
96-
Err(ParseAmountError::OutOfRange(OutOfRangeError::too_big(true))),
96+
(false, sat) if sat > i64::MAX as u64 => Err(ParseAmountError(
97+
ParseAmountErrorInner::OutOfRange(OutOfRangeError::too_big(true)),
98+
)),
9799
(false, sat) => Ok(SignedAmount(sat as i64)),
98100
(true, sat) if sat == i64::MIN.unsigned_abs() => Ok(SignedAmount(i64::MIN)),
99-
(true, sat) if sat > i64::MIN.unsigned_abs() =>
100-
Err(ParseAmountError::OutOfRange(OutOfRangeError::too_small())),
101+
(true, sat) if sat > i64::MIN.unsigned_abs() => Err(ParseAmountError(
102+
ParseAmountErrorInner::OutOfRange(OutOfRangeError::too_small()),
103+
)),
101104
(true, sat) => Ok(SignedAmount(-(sat as i64))),
102105
}
103106
}
@@ -415,7 +418,7 @@ impl FromStr for SignedAmount {
415418
let result = SignedAmount::from_str_with_denomination(s);
416419

417420
match result {
418-
Err(ParseError::MissingDenomination(_)) => {
421+
Err(ParseError(ParseErrorInner::MissingDenomination(_))) => {
419422
let d = SignedAmount::from_str_in(s, Denomination::Satoshi);
420423

421424
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
@@ -12,6 +12,7 @@ use ::serde::{Deserialize, Serialize};
1212
#[cfg(feature = "arbitrary")]
1313
use arbitrary::{Arbitrary, Unstructured};
1414

15+
use super::error::{ParseAmountErrorInner, ParseErrorInner};
1516
use super::{
1617
parse_signed_to_satoshi, split_amount_and_denomination, Denomination, Display, DisplayStyle,
1718
OutOfRangeError, ParseAmountError, ParseError, SignedAmount,
@@ -103,7 +104,9 @@ impl Amount {
103104
let (negative, satoshi) =
104105
parse_signed_to_satoshi(s, denom).map_err(|error| error.convert(false))?;
105106
if negative {
106-
return Err(ParseAmountError::OutOfRange(OutOfRangeError::negative()));
107+
return Err(ParseAmountError(ParseAmountErrorInner::OutOfRange(
108+
OutOfRangeError::negative(),
109+
)));
107110
}
108111
Ok(Amount::from_sat(satoshi))
109112
}
@@ -405,7 +408,7 @@ impl FromStr for Amount {
405408
let result = Amount::from_str_with_denomination(s);
406409

407410
match result {
408-
Err(ParseError::MissingDenomination(_)) => {
411+
Err(ParseError(ParseErrorInner::MissingDenomination(_))) => {
409412
let d = Amount::from_str_in(s, Denomination::Satoshi);
410413

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

0 commit comments

Comments
 (0)