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