1use core::convert::Infallible;
6use core::fmt;
7
8use internals::error::InputString;
9use internals::write_err;
10
11use super::INPUT_STRING_LEN_LIMIT;
12
13#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct ParseError(pub(crate) ParseErrorInner);
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub(crate) enum ParseErrorInner {
19 Amount(ParseAmountError),
21 Denomination(ParseDenominationError),
23 MissingDenomination(MissingDenominationError),
25}
26
27impl From<Infallible> for ParseError {
28 fn from(never: Infallible) -> Self { match never {} }
29}
30
31impl From<Infallible> for ParseErrorInner {
32 fn from(never: Infallible) -> Self { match never {} }
33}
34
35impl From<ParseAmountError> for ParseError {
36 fn from(e: ParseAmountError) -> Self { Self(ParseErrorInner::Amount(e)) }
37}
38
39impl From<ParseDenominationError> for ParseError {
40 fn from(e: ParseDenominationError) -> Self { Self(ParseErrorInner::Denomination(e)) }
41}
42
43impl From<OutOfRangeError> for ParseError {
44 fn from(e: OutOfRangeError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
45}
46
47impl From<TooPreciseError> for ParseError {
48 fn from(e: TooPreciseError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
49}
50
51impl From<MissingDigitsError> for ParseError {
52 fn from(e: MissingDigitsError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
53}
54
55impl From<InputTooLargeError> for ParseError {
56 fn from(e: InputTooLargeError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
57}
58
59impl From<InvalidCharacterError> for ParseError {
60 fn from(e: InvalidCharacterError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
61}
62
63impl From<BadPositionError> for ParseError {
64 fn from(e: BadPositionError) -> Self { Self(ParseErrorInner::Amount(e.into())) }
65}
66
67impl fmt::Display for ParseError {
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 match self.0 {
70 ParseErrorInner::Amount(ref e) => write_err!(f, "invalid amount"; e),
71 ParseErrorInner::Denomination(ref e) => write_err!(f, "invalid denomination"; e),
72 ParseErrorInner::MissingDenomination(_) =>
74 f.write_str("the input doesn't contain a denomination"),
75 }
76 }
77}
78
79#[cfg(feature = "std")]
80impl std::error::Error for ParseError {
81 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
82 match self.0 {
83 ParseErrorInner::Amount(ref e) => Some(e),
84 ParseErrorInner::Denomination(ref e) => Some(e),
85 ParseErrorInner::MissingDenomination(_) => None,
87 }
88 }
89}
90
91#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct ParseAmountError(pub(crate) ParseAmountErrorInner);
94
95#[derive(Debug, Clone, PartialEq, Eq)]
96pub(crate) enum ParseAmountErrorInner {
97 OutOfRange(OutOfRangeError),
99 TooPrecise(TooPreciseError),
101 MissingDigits(MissingDigitsError),
103 InputTooLarge(InputTooLargeError),
105 InvalidCharacter(InvalidCharacterError),
107 BadPosition(BadPositionError),
109}
110
111impl From<TooPreciseError> for ParseAmountError {
112 fn from(value: TooPreciseError) -> Self { Self(ParseAmountErrorInner::TooPrecise(value)) }
113}
114
115impl From<MissingDigitsError> for ParseAmountError {
116 fn from(value: MissingDigitsError) -> Self { Self(ParseAmountErrorInner::MissingDigits(value)) }
117}
118
119impl From<InputTooLargeError> for ParseAmountError {
120 fn from(value: InputTooLargeError) -> Self { Self(ParseAmountErrorInner::InputTooLarge(value)) }
121}
122
123impl From<InvalidCharacterError> for ParseAmountError {
124 fn from(value: InvalidCharacterError) -> Self {
125 Self(ParseAmountErrorInner::InvalidCharacter(value))
126 }
127}
128
129impl From<BadPositionError> for ParseAmountError {
130 fn from(value: BadPositionError) -> Self { Self(ParseAmountErrorInner::BadPosition(value)) }
131}
132
133impl From<Infallible> for ParseAmountError {
134 fn from(never: Infallible) -> Self { match never {} }
135}
136
137impl From<Infallible> for ParseAmountErrorInner {
138 fn from(never: Infallible) -> Self { match never {} }
139}
140
141impl fmt::Display for ParseAmountError {
142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143 use ParseAmountErrorInner as E;
144
145 match self.0 {
146 E::OutOfRange(ref error) => write_err!(f, "amount out of range"; error),
147 E::TooPrecise(ref error) => write_err!(f, "amount has a too high precision"; error),
148 E::MissingDigits(ref error) => write_err!(f, "the input has too few digits"; error),
149 E::InputTooLarge(ref error) => write_err!(f, "the input is too large"; error),
150 E::InvalidCharacter(ref error) => {
151 write_err!(f, "invalid character in the input"; error)
152 }
153 E::BadPosition(ref error) => write_err!(f, "valid character in bad position"; error),
154 }
155 }
156}
157
158#[cfg(feature = "std")]
159impl std::error::Error for ParseAmountError {
160 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
161 use ParseAmountErrorInner as E;
162
163 match self.0 {
164 E::TooPrecise(ref error) => Some(error),
165 E::InputTooLarge(ref error) => Some(error),
166 E::OutOfRange(ref error) => Some(error),
167 E::MissingDigits(ref error) => Some(error),
168 E::InvalidCharacter(ref error) => Some(error),
169 E::BadPosition(ref error) => Some(error),
170 }
171 }
172}
173
174#[derive(Debug, Copy, Clone, Eq, PartialEq)]
176pub struct OutOfRangeError {
177 pub(super) is_signed: bool,
178 pub(super) is_greater_than_max: bool,
179}
180
181impl OutOfRangeError {
182 pub fn valid_range(self) -> (i64, u64) {
186 match self.is_signed {
187 true => (i64::MIN, i64::MAX as u64),
188 false => (0, u64::MAX),
189 }
190 }
191
192 pub fn is_above_max(self) -> bool { self.is_greater_than_max }
194
195 pub fn is_below_min(self) -> bool { !self.is_greater_than_max }
197
198 #[cfg(test)]
199 pub(crate) fn too_big(is_signed: bool) -> Self { Self { is_signed, is_greater_than_max: true } }
200
201 #[cfg(test)]
202 pub(crate) fn too_small() -> Self {
203 Self {
204 is_signed: true,
206 is_greater_than_max: false,
207 }
208 }
209
210 pub(crate) fn negative() -> Self {
211 Self {
212 is_signed: false,
214 is_greater_than_max: false,
215 }
216 }
217}
218
219impl fmt::Display for OutOfRangeError {
220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221 if self.is_greater_than_max {
222 write!(f, "the amount is greater than {}", self.valid_range().1)
223 } else {
224 write!(f, "the amount is less than {}", self.valid_range().0)
225 }
226 }
227}
228
229#[cfg(feature = "std")]
230impl std::error::Error for OutOfRangeError {}
231
232impl From<OutOfRangeError> for ParseAmountError {
233 fn from(value: OutOfRangeError) -> Self { Self(ParseAmountErrorInner::OutOfRange(value)) }
234}
235
236#[derive(Debug, Clone, Eq, PartialEq)]
238pub struct TooPreciseError {
239 pub(super) position: usize,
240}
241
242impl fmt::Display for TooPreciseError {
243 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
244 match self.position {
245 0 => f.write_str("the amount is less than 1 satoshi but it's not zero"),
246 pos => write!(
247 f,
248 "the digits starting from position {} represent a sub-satoshi amount",
249 pos
250 ),
251 }
252 }
253}
254
255#[cfg(feature = "std")]
256impl std::error::Error for TooPreciseError {}
257
258#[derive(Debug, Clone, Eq, PartialEq)]
260pub struct InputTooLargeError {
261 pub(super) len: usize,
262}
263
264impl fmt::Display for InputTooLargeError {
265 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
266 match self.len - INPUT_STRING_LEN_LIMIT {
267 1 => write!(
268 f,
269 "the input is one character longer than the maximum allowed length ({})",
270 INPUT_STRING_LEN_LIMIT
271 ),
272 n => write!(
273 f,
274 "the input is {} characters longer than the maximum allowed length ({})",
275 n, INPUT_STRING_LEN_LIMIT
276 ),
277 }
278 }
279}
280
281#[cfg(feature = "std")]
282impl std::error::Error for InputTooLargeError {}
283
284#[derive(Debug, Clone, Eq, PartialEq)]
288pub struct MissingDigitsError {
289 pub(super) kind: MissingDigitsKind,
290}
291
292impl fmt::Display for MissingDigitsError {
293 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
294 match self.kind {
295 MissingDigitsKind::Empty => f.write_str("the input is empty"),
296 MissingDigitsKind::OnlyMinusSign =>
297 f.write_str("there are no digits following the minus (-) sign"),
298 }
299 }
300}
301
302#[cfg(feature = "std")]
303impl std::error::Error for MissingDigitsError {}
304
305#[derive(Debug, Clone, Eq, PartialEq)]
306pub(super) enum MissingDigitsKind {
307 Empty,
308 OnlyMinusSign,
309}
310
311#[derive(Debug, Clone, PartialEq, Eq)]
313pub struct InvalidCharacterError {
314 pub(super) invalid_char: char,
315 pub(super) position: usize,
316}
317
318impl fmt::Display for InvalidCharacterError {
319 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320 match self.invalid_char {
321 '.' => f.write_str("there is more than one decimal separator (dot) in the input"),
322 '-' => f.write_str("there is more than one minus sign (-) in the input"),
323 c => write!(
324 f,
325 "the character '{}' at position {} is not a valid digit",
326 c, self.position
327 ),
328 }
329 }
330}
331
332#[cfg(feature = "std")]
333impl std::error::Error for InvalidCharacterError {}
334
335#[derive(Debug, Clone, PartialEq, Eq)]
337pub struct BadPositionError {
338 pub(super) char: char,
339 pub(super) position: usize,
340}
341
342impl fmt::Display for BadPositionError {
343 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
344 match self.char {
345 '_' => match self.position {
346 0 => f.write_str("the input amount is prefixed with an underscore (_)"),
347 1 => f.write_str("the input amount is prefixed with an underscore (_)"),
351 _ => f.write_str("there are consecutive underscores (_) in the input"),
352 },
353 c => write!(f, "The character '{}' is at a bad position: {}", c, self.position),
354 }
355 }
356}
357
358#[cfg(feature = "std")]
359impl std::error::Error for BadPositionError {}
360
361#[derive(Debug, Clone, PartialEq, Eq)]
363#[non_exhaustive]
364pub enum ParseDenominationError {
365 Unknown(UnknownDenominationError),
367 PossiblyConfusing(PossiblyConfusingDenominationError),
369}
370
371impl From<Infallible> for ParseDenominationError {
372 fn from(never: Infallible) -> Self { match never {} }
373}
374
375impl fmt::Display for ParseDenominationError {
376 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
377 match *self {
378 Self::Unknown(ref e) => write_err!(f, "denomination parse error"; e),
379 Self::PossiblyConfusing(ref e) => write_err!(f, "denomination parse error"; e),
380 }
381 }
382}
383
384#[cfg(feature = "std")]
385impl std::error::Error for ParseDenominationError {
386 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
387 match *self {
388 Self::Unknown(_) | Self::PossiblyConfusing(_) => None,
389 }
390 }
391}
392
393#[derive(Debug, Clone, PartialEq, Eq)]
395#[non_exhaustive]
396pub struct MissingDenominationError;
397
398#[derive(Debug, Clone, PartialEq, Eq)]
400#[non_exhaustive]
401pub struct UnknownDenominationError(pub(super) InputString);
402
403impl fmt::Display for UnknownDenominationError {
404 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
405 self.0.unknown_variant("bitcoin denomination", f)
406 }
407}
408
409#[cfg(feature = "std")]
410impl std::error::Error for UnknownDenominationError {
411 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
412}
413
414#[derive(Debug, Clone, PartialEq, Eq)]
416#[non_exhaustive]
417pub struct PossiblyConfusingDenominationError(pub(super) InputString);
418
419impl fmt::Display for PossiblyConfusingDenominationError {
420 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
421 write!(f, "{}: possibly confusing denomination - we intentionally do not support 'M' and 'P' so as to not confuse mega/milli and peta/pico", self.0.display_cannot_parse("bitcoin denomination"))
422 }
423}
424
425#[cfg(feature = "std")]
426impl std::error::Error for PossiblyConfusingDenominationError {
427 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
428}
429
430#[cfg(feature = "encoding")]
432#[derive(Debug, Clone, PartialEq, Eq)]
433pub struct AmountDecoderError(pub(super) AmountDecoderErrorInner);
434
435#[cfg(feature = "encoding")]
436impl AmountDecoderError {
437 pub(super) fn eof(e: encoding::UnexpectedEofError) -> Self {
439 Self(AmountDecoderErrorInner::UnexpectedEof(e))
440 }
441
442 pub(super) fn out_of_range(e: OutOfRangeError) -> Self {
444 Self(AmountDecoderErrorInner::OutOfRange(e))
445 }
446}
447
448#[cfg(feature = "encoding")]
449#[derive(Debug, Clone, PartialEq, Eq)]
450pub(super) enum AmountDecoderErrorInner {
451 UnexpectedEof(encoding::UnexpectedEofError),
453 OutOfRange(OutOfRangeError),
455}
456
457#[cfg(feature = "encoding")]
458impl From<Infallible> for AmountDecoderError {
459 fn from(never: Infallible) -> Self { match never {} }
460}
461
462#[cfg(feature = "encoding")]
463impl fmt::Display for AmountDecoderError {
464 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
465 use AmountDecoderErrorInner as E;
466
467 match self.0 {
468 E::UnexpectedEof(ref e) => write_err!(f, "decode error"; e),
469 E::OutOfRange(ref e) => write_err!(f, "decode error"; e),
470 }
471 }
472}
473
474#[cfg(all(feature = "std", feature = "encoding"))]
475impl std::error::Error for AmountDecoderError {
476 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
477 use AmountDecoderErrorInner as E;
478
479 match self.0 {
480 E::UnexpectedEof(ref e) => Some(e),
481 E::OutOfRange(ref e) => Some(e),
482 }
483 }
484}