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