1use alloc::string::{String, ToString};
2use core::fmt;
3
4use super::{impl_from_err, BT};
5
6use crate::errors::{RecoverPubkeyError, VerificationError};
7
8#[derive(Debug, thiserror::Error)]
24pub enum StdError {
25 #[error("Verification error: {source}")]
26 VerificationErr {
27 source: VerificationError,
28 backtrace: BT,
29 },
30 #[error("Recover pubkey error: {source}")]
31 RecoverPubkeyErr {
32 source: RecoverPubkeyError,
33 backtrace: BT,
34 },
35 #[error("Generic error: {msg}")]
37 GenericErr { msg: String, backtrace: BT },
38 #[error("Invalid Base64 string: {msg}")]
39 InvalidBase64 { msg: String, backtrace: BT },
40 #[error("Invalid data size: expected={expected} actual={actual}")]
41 InvalidDataSize {
42 expected: u64,
43 actual: u64,
44 backtrace: BT,
45 },
46 #[error("Invalid hex string: {msg}")]
47 InvalidHex { msg: String, backtrace: BT },
48 #[error("Cannot decode UTF8 bytes into string: {msg}")]
50 InvalidUtf8 { msg: String, backtrace: BT },
51 #[error("{kind} not found")]
52 NotFound { kind: String, backtrace: BT },
53 #[error("Error parsing into type {target_type}: {msg}")]
54 ParseErr {
55 target_type: String,
57 msg: String,
58 backtrace: BT,
59 },
60 #[error("Error serializing type {source_type}: {msg}")]
61 SerializeErr {
62 source_type: String,
64 msg: String,
65 backtrace: BT,
66 },
67 #[error("Overflow: {source}")]
68 Overflow {
69 source: OverflowError,
70 backtrace: BT,
71 },
72 #[error("Divide by zero: {source}")]
73 DivideByZero {
74 source: DivideByZeroError,
75 backtrace: BT,
76 },
77 #[error("Conversion error: ")]
78 ConversionOverflow {
79 source: ConversionOverflowError,
80 backtrace: BT,
81 },
82}
83
84impl_from_err!(
85 ConversionOverflowError,
86 StdError,
87 StdError::ConversionOverflow
88);
89
90impl StdError {
91 pub fn verification_err(source: VerificationError) -> Self {
92 StdError::VerificationErr {
93 source,
94 backtrace: BT::capture(),
95 }
96 }
97
98 pub fn recover_pubkey_err(source: RecoverPubkeyError) -> Self {
99 StdError::RecoverPubkeyErr {
100 source,
101 backtrace: BT::capture(),
102 }
103 }
104
105 pub fn generic_err(msg: impl Into<String>) -> Self {
106 StdError::GenericErr {
107 msg: msg.into(),
108 backtrace: BT::capture(),
109 }
110 }
111
112 pub fn invalid_base64(msg: impl ToString) -> Self {
113 StdError::InvalidBase64 {
114 msg: msg.to_string(),
115 backtrace: BT::capture(),
116 }
117 }
118
119 pub fn invalid_data_size(expected: usize, actual: usize) -> Self {
120 StdError::InvalidDataSize {
121 expected: expected as u64,
123 actual: actual as u64,
124 backtrace: BT::capture(),
125 }
126 }
127
128 pub fn invalid_hex(msg: impl ToString) -> Self {
129 StdError::InvalidHex {
130 msg: msg.to_string(),
131 backtrace: BT::capture(),
132 }
133 }
134
135 pub fn invalid_utf8(msg: impl ToString) -> Self {
136 StdError::InvalidUtf8 {
137 msg: msg.to_string(),
138 backtrace: BT::capture(),
139 }
140 }
141
142 pub fn not_found(kind: impl Into<String>) -> Self {
143 StdError::NotFound {
144 kind: kind.into(),
145 backtrace: BT::capture(),
146 }
147 }
148
149 pub fn parse_err(target: impl Into<String>, msg: impl ToString) -> Self {
150 StdError::ParseErr {
151 target_type: target.into(),
152 msg: msg.to_string(),
153 backtrace: BT::capture(),
154 }
155 }
156
157 pub fn serialize_err(source: impl Into<String>, msg: impl ToString) -> Self {
158 StdError::SerializeErr {
159 source_type: source.into(),
160 msg: msg.to_string(),
161 backtrace: BT::capture(),
162 }
163 }
164
165 pub fn overflow(source: OverflowError) -> Self {
166 StdError::Overflow {
167 source,
168 backtrace: BT::capture(),
169 }
170 }
171
172 pub fn divide_by_zero(source: DivideByZeroError) -> Self {
173 StdError::DivideByZero {
174 source,
175 backtrace: BT::capture(),
176 }
177 }
178}
179
180impl PartialEq<StdError> for StdError {
181 fn eq(&self, rhs: &StdError) -> bool {
182 match self {
183 StdError::VerificationErr {
184 source,
185 backtrace: _,
186 } => {
187 if let StdError::VerificationErr {
188 source: rhs_source,
189 backtrace: _,
190 } = rhs
191 {
192 source == rhs_source
193 } else {
194 false
195 }
196 }
197 StdError::RecoverPubkeyErr {
198 source,
199 backtrace: _,
200 } => {
201 if let StdError::RecoverPubkeyErr {
202 source: rhs_source,
203 backtrace: _,
204 } = rhs
205 {
206 source == rhs_source
207 } else {
208 false
209 }
210 }
211 StdError::GenericErr { msg, backtrace: _ } => {
212 if let StdError::GenericErr {
213 msg: rhs_msg,
214 backtrace: _,
215 } = rhs
216 {
217 msg == rhs_msg
218 } else {
219 false
220 }
221 }
222 StdError::InvalidBase64 { msg, backtrace: _ } => {
223 if let StdError::InvalidBase64 {
224 msg: rhs_msg,
225 backtrace: _,
226 } = rhs
227 {
228 msg == rhs_msg
229 } else {
230 false
231 }
232 }
233 StdError::InvalidDataSize {
234 expected,
235 actual,
236 backtrace: _,
237 } => {
238 if let StdError::InvalidDataSize {
239 expected: rhs_expected,
240 actual: rhs_actual,
241 backtrace: _,
242 } = rhs
243 {
244 expected == rhs_expected && actual == rhs_actual
245 } else {
246 false
247 }
248 }
249 StdError::InvalidHex { msg, backtrace: _ } => {
250 if let StdError::InvalidHex {
251 msg: rhs_msg,
252 backtrace: _,
253 } = rhs
254 {
255 msg == rhs_msg
256 } else {
257 false
258 }
259 }
260 StdError::InvalidUtf8 { msg, backtrace: _ } => {
261 if let StdError::InvalidUtf8 {
262 msg: rhs_msg,
263 backtrace: _,
264 } = rhs
265 {
266 msg == rhs_msg
267 } else {
268 false
269 }
270 }
271 StdError::NotFound { kind, backtrace: _ } => {
272 if let StdError::NotFound {
273 kind: rhs_kind,
274 backtrace: _,
275 } = rhs
276 {
277 kind == rhs_kind
278 } else {
279 false
280 }
281 }
282 StdError::ParseErr {
283 target_type,
284 msg,
285 backtrace: _,
286 } => {
287 if let StdError::ParseErr {
288 target_type: rhs_target_type,
289 msg: rhs_msg,
290 backtrace: _,
291 } = rhs
292 {
293 target_type == rhs_target_type && msg == rhs_msg
294 } else {
295 false
296 }
297 }
298 StdError::SerializeErr {
299 source_type,
300 msg,
301 backtrace: _,
302 } => {
303 if let StdError::SerializeErr {
304 source_type: rhs_source_type,
305 msg: rhs_msg,
306 backtrace: _,
307 } = rhs
308 {
309 source_type == rhs_source_type && msg == rhs_msg
310 } else {
311 false
312 }
313 }
314 StdError::Overflow {
315 source,
316 backtrace: _,
317 } => {
318 if let StdError::Overflow {
319 source: rhs_source,
320 backtrace: _,
321 } = rhs
322 {
323 source == rhs_source
324 } else {
325 false
326 }
327 }
328 StdError::DivideByZero {
329 source,
330 backtrace: _,
331 } => {
332 if let StdError::DivideByZero {
333 source: rhs_source,
334 backtrace: _,
335 } = rhs
336 {
337 source == rhs_source
338 } else {
339 false
340 }
341 }
342 StdError::ConversionOverflow {
343 source,
344 backtrace: _,
345 } => {
346 if let StdError::ConversionOverflow {
347 source: rhs_source,
348 backtrace: _,
349 } = rhs
350 {
351 source == rhs_source
352 } else {
353 false
354 }
355 }
356 }
357 }
358}
359
360impl From<core::str::Utf8Error> for StdError {
361 fn from(source: core::str::Utf8Error) -> Self {
362 Self::invalid_utf8(source)
363 }
364}
365
366impl From<alloc::string::FromUtf8Error> for StdError {
367 fn from(source: alloc::string::FromUtf8Error) -> Self {
368 Self::invalid_utf8(source)
369 }
370}
371
372impl From<VerificationError> for StdError {
373 fn from(source: VerificationError) -> Self {
374 Self::verification_err(source)
375 }
376}
377
378impl From<RecoverPubkeyError> for StdError {
379 fn from(source: RecoverPubkeyError) -> Self {
380 Self::recover_pubkey_err(source)
381 }
382}
383
384impl From<OverflowError> for StdError {
385 fn from(source: OverflowError) -> Self {
386 Self::overflow(source)
387 }
388}
389
390impl From<DivideByZeroError> for StdError {
391 fn from(source: DivideByZeroError) -> Self {
392 Self::divide_by_zero(source)
393 }
394}
395
396pub type StdResult<T> = core::result::Result<T, StdError>;
402
403#[derive(Debug, PartialEq, Eq)]
404pub enum OverflowOperation {
405 Add,
406 Sub,
407 Mul,
408 Pow,
409 Shr,
410 Shl,
411}
412
413impl fmt::Display for OverflowOperation {
414 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
415 write!(f, "{self:?}")
416 }
417}
418
419#[derive(Debug, PartialEq, Eq, thiserror::Error)]
420#[error("Cannot {operation} with given operands")]
421pub struct OverflowError {
422 pub operation: OverflowOperation,
423}
424
425impl OverflowError {
426 pub fn new(operation: OverflowOperation) -> Self {
427 Self { operation }
428 }
429}
430
431#[derive(Debug, PartialEq, Eq, thiserror::Error)]
438#[error("Error converting {source_type} to {target_type}")]
439pub struct ConversionOverflowError {
440 pub source_type: &'static str,
441 pub target_type: &'static str,
442}
443
444impl ConversionOverflowError {
445 pub fn new(source_type: &'static str, target_type: &'static str) -> Self {
446 Self {
447 source_type,
448 target_type,
449 }
450 }
451}
452
453#[derive(Debug, Default, PartialEq, Eq, thiserror::Error)]
454#[error("Cannot divide by zero")]
455pub struct DivideByZeroError;
456
457impl DivideByZeroError {
458 pub fn new() -> Self {
459 Self
460 }
461}
462
463#[derive(Debug, PartialEq, Eq, thiserror::Error)]
464pub enum DivisionError {
465 #[error("Divide by zero")]
466 DivideByZero,
467
468 #[error("Overflow in division")]
469 Overflow,
470}
471
472#[derive(Debug, PartialEq, Eq, thiserror::Error)]
473pub enum CheckedMultiplyFractionError {
474 #[error("{_0}")]
475 DivideByZero(#[from] DivideByZeroError),
476
477 #[error("{_0}")]
478 ConversionOverflow(#[from] ConversionOverflowError),
479
480 #[error("{_0}")]
481 Overflow(#[from] OverflowError),
482}
483
484#[derive(Debug, PartialEq, Eq, thiserror::Error)]
485pub enum CheckedMultiplyRatioError {
486 #[error("Denominator must not be zero")]
487 DivideByZero,
488
489 #[error("Multiplication overflow")]
490 Overflow,
491}
492
493#[derive(Debug, PartialEq, Eq, thiserror::Error)]
494pub enum CheckedFromRatioError {
495 #[error("Denominator must not be zero")]
496 DivideByZero,
497
498 #[error("Overflow")]
499 Overflow,
500}
501
502#[derive(Debug, PartialEq, Eq, thiserror::Error)]
503#[error("Round up operation failed because of overflow")]
504pub struct RoundUpOverflowError;
505
506#[derive(Debug, PartialEq, Eq, thiserror::Error)]
507#[error("Round down operation failed because of overflow")]
508pub struct RoundDownOverflowError;
509
510#[derive(Debug, PartialEq, Eq, thiserror::Error)]
511pub enum CoinsError {
512 #[error("Duplicate denom")]
513 DuplicateDenom,
514}
515
516impl From<CoinsError> for StdError {
517 fn from(value: CoinsError) -> Self {
518 Self::generic_err(format!("Creating Coins: {value}"))
519 }
520}
521
522#[derive(Debug, PartialEq, Eq, thiserror::Error)]
523pub enum CoinFromStrError {
524 #[error("Missing denominator")]
525 MissingDenom,
526 #[error("Missing amount or non-digit characters in amount")]
527 MissingAmount,
528 #[error("Invalid amount: {_0}")]
529 InvalidAmount(core::num::ParseIntError),
530}
531
532impl From<core::num::ParseIntError> for CoinFromStrError {
533 fn from(value: core::num::ParseIntError) -> Self {
534 Self::InvalidAmount(value)
535 }
536}
537
538impl From<CoinFromStrError> for StdError {
539 fn from(value: CoinFromStrError) -> Self {
540 Self::generic_err(format!("Parsing Coin: {value}"))
541 }
542}
543
544#[cfg(test)]
545mod tests {
546 use super::*;
547 use core::str;
548
549 #[test]
553 fn generic_err_owned() {
554 let guess = 7;
555 let error = StdError::generic_err(format!("{guess} is too low"));
556 match error {
557 StdError::GenericErr { msg, .. } => {
558 assert_eq!(msg, String::from("7 is too low"));
559 }
560 e => panic!("unexpected error, {e:?}"),
561 }
562 }
563
564 #[test]
566 fn generic_err_ref() {
567 let error = StdError::generic_err("not implemented");
568 match error {
569 StdError::GenericErr { msg, .. } => assert_eq!(msg, "not implemented"),
570 e => panic!("unexpected error, {e:?}"),
571 }
572 }
573
574 #[test]
575 fn invalid_base64_works_for_strings() {
576 let error = StdError::invalid_base64("my text");
577 match error {
578 StdError::InvalidBase64 { msg, .. } => {
579 assert_eq!(msg, "my text");
580 }
581 _ => panic!("expect different error"),
582 }
583 }
584
585 #[test]
586 fn invalid_base64_works_for_errors() {
587 let original = base64::DecodeError::InvalidLength(10);
588 let error = StdError::invalid_base64(original);
589 match error {
590 StdError::InvalidBase64 { msg, .. } => {
591 assert_eq!(msg, "Invalid input length: 10");
592 }
593 _ => panic!("expect different error"),
594 }
595 }
596
597 #[test]
598 fn invalid_data_size_works() {
599 let error = StdError::invalid_data_size(31, 14);
600 match error {
601 StdError::InvalidDataSize {
602 expected, actual, ..
603 } => {
604 assert_eq!(expected, 31);
605 assert_eq!(actual, 14);
606 }
607 _ => panic!("expect different error"),
608 }
609 }
610
611 #[test]
612 fn invalid_hex_works_for_strings() {
613 let error = StdError::invalid_hex("my text");
614 match error {
615 StdError::InvalidHex { msg, .. } => {
616 assert_eq!(msg, "my text");
617 }
618 _ => panic!("expect different error"),
619 }
620 }
621
622 #[test]
623 fn invalid_hex_works_for_errors() {
624 let original = hex::FromHexError::OddLength;
625 let error = StdError::invalid_hex(original);
626 match error {
627 StdError::InvalidHex { msg, .. } => {
628 assert_eq!(msg, "Odd number of digits");
629 }
630 _ => panic!("expect different error"),
631 }
632 }
633
634 #[test]
635 fn invalid_utf8_works_for_strings() {
636 let error = StdError::invalid_utf8("my text");
637 match error {
638 StdError::InvalidUtf8 { msg, .. } => {
639 assert_eq!(msg, "my text");
640 }
641 _ => panic!("expect different error"),
642 }
643 }
644
645 #[test]
646 fn invalid_utf8_works_for_errors() {
647 let original = String::from_utf8(vec![0x80]).unwrap_err();
648 let error = StdError::invalid_utf8(original);
649 match error {
650 StdError::InvalidUtf8 { msg, .. } => {
651 assert_eq!(msg, "invalid utf-8 sequence of 1 bytes from index 0");
652 }
653 _ => panic!("expect different error"),
654 }
655 }
656
657 #[test]
658 fn not_found_works() {
659 let error = StdError::not_found("gold");
660 match error {
661 StdError::NotFound { kind, .. } => assert_eq!(kind, "gold"),
662 _ => panic!("expect different error"),
663 }
664 }
665
666 #[test]
667 fn parse_err_works() {
668 let error = StdError::parse_err("Book", "Missing field: title");
669 match error {
670 StdError::ParseErr {
671 target_type, msg, ..
672 } => {
673 assert_eq!(target_type, "Book");
674 assert_eq!(msg, "Missing field: title");
675 }
676 _ => panic!("expect different error"),
677 }
678 }
679
680 #[test]
681 fn serialize_err_works() {
682 let error = StdError::serialize_err("Book", "Content too long");
683 match error {
684 StdError::SerializeErr {
685 source_type, msg, ..
686 } => {
687 assert_eq!(source_type, "Book");
688 assert_eq!(msg, "Content too long");
689 }
690 _ => panic!("expect different error"),
691 }
692 }
693
694 #[test]
695 fn underflow_works_for_u128() {
696 let error = StdError::overflow(OverflowError::new(OverflowOperation::Sub));
697 assert!(matches!(
698 error,
699 StdError::Overflow {
700 source: OverflowError {
701 operation: OverflowOperation::Sub
702 },
703 ..
704 }
705 ));
706 }
707
708 #[test]
709 fn overflow_works_for_i64() {
710 let error = StdError::overflow(OverflowError::new(OverflowOperation::Sub));
711 assert!(matches!(
712 error,
713 StdError::Overflow {
714 source: OverflowError {
715 operation: OverflowOperation::Sub
716 },
717 ..
718 }
719 ));
720 }
721
722 #[test]
723 fn divide_by_zero_works() {
724 let error = StdError::divide_by_zero(DivideByZeroError);
725 assert!(matches!(
726 error,
727 StdError::DivideByZero {
728 source: DivideByZeroError,
729 ..
730 }
731 ));
732 }
733
734 #[test]
735 fn implements_debug() {
736 let error: StdError = StdError::from(OverflowError::new(OverflowOperation::Sub));
737 let embedded = format!("Debug: {error:?}");
738 assert!(embedded
739 .starts_with("Debug: Overflow { source: OverflowError { operation: Sub }, backtrace:"));
740 }
741
742 #[test]
743 fn implements_display() {
744 let error: StdError = StdError::from(OverflowError::new(OverflowOperation::Sub));
745 let embedded = format!("Display: {error}");
746 assert_eq!(
747 embedded,
748 "Display: Overflow: Cannot Sub with given operands"
749 );
750 }
751
752 #[test]
753 fn implements_partial_eq() {
754 let u1 = StdError::from(OverflowError::new(OverflowOperation::Sub));
755 let u2 = StdError::from(OverflowError::new(OverflowOperation::Sub));
756 let s1 = StdError::serialize_err("Book", "Content too long");
757 let s2 = StdError::serialize_err("Book", "Content too long");
758 let s3 = StdError::serialize_err("Book", "Title too long");
759 assert_eq!(u1, u2);
760 assert_ne!(u1, s1);
761 assert_eq!(s1, s2);
762 assert_ne!(s1, s3);
763 }
764
765 #[test]
766 fn from_std_str_utf8error_works() {
767 let broken = Vec::from(b"Hello \xF0\x90\x80World" as &[u8]);
768 let error: StdError = str::from_utf8(&broken).unwrap_err().into();
769 match error {
770 StdError::InvalidUtf8 { msg, .. } => {
771 assert_eq!(msg, "invalid utf-8 sequence of 3 bytes from index 6")
772 }
773 err => panic!("Unexpected error: {err:?}"),
774 }
775 }
776
777 #[test]
778 fn from_std_string_from_utf8error_works() {
779 let error: StdError = String::from_utf8(b"Hello \xF0\x90\x80World".to_vec())
780 .unwrap_err()
781 .into();
782 match error {
783 StdError::InvalidUtf8 { msg, .. } => {
784 assert_eq!(msg, "invalid utf-8 sequence of 3 bytes from index 6")
785 }
786 err => panic!("Unexpected error: {err:?}"),
787 }
788 }
789}