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