bitcoin_internals/error/mod.rs
1// SPDX-License-Identifier: CC0-1.0
2
3//! # Error
4//!
5//! Error handling macros and helpers.
6
7#[cfg(not(creusot))]
8pub mod input_string;
9mod parse_error;
10
11#[cfg(not(creusot))]
12pub use input_string::InputString;
13
14#[doc(hidden)]
15/// Helper trait for checking whether something implements [`std::error::Error`].
16///
17/// We use helper trait instead of function to make the compiler handle auto dereferencing.
18#[cfg(feature = "std")]
19pub trait ErrorExt: std::error::Error + 'static {
20 /// Does nothing, just call it
21 #[inline(always)]
22 fn check_is_actually_error_source(&self) {}
23}
24
25#[doc(hidden)]
26#[cfg(feature = "std")]
27impl<T: std::error::Error + 'static> ErrorExt for T {}
28
29/// Formats error.
30///
31/// If `std` feature is OFF appends error source (delimited by `: `). We do this because
32/// `e.source()` is only available in std builds, without this macro the error source is lost for
33/// no-std builds.
34///
35/// Note: will not compile on std if $source doesn't implement [`std::error::Error`]. This is
36/// intentional because if it doesn't the macro MUST NOT be used. However this check is very rarely
37/// imprecise so if you know what you're doing you can use the unchecked version.
38#[macro_export]
39macro_rules! write_err {
40 ($writer:expr, $string:literal $(, $args:expr)*; $source:expr) => {
41 {
42 #[cfg(feature = "std")]
43 {
44 use $crate::error::ErrorExt;
45
46 // Enforces that $source is actually an error.
47 //
48 // Occasionally people accidentally use write_err! with non-error and it's quite
49 // hard to detect otherwise so this gives them compilation error.
50 // Also avoids lints saying $source is unused.
51 ($source).check_is_actually_error_source();
52
53 write!($writer, $string $(, $args)*)
54 }
55 #[cfg(not(feature = "std"))]
56 {
57 write!($writer, concat!($string, ": {}") $(, $args)*, $source)
58 }
59 }
60 }
61}
62
63/// Formats error.
64///
65/// Unlike [`write_err`] doesn't statically check that `$source` implements `std::error::Error`.
66/// This should be used only in rare generic situations. Specifically, in case of a generic
67/// `MyError<Error>`, this macro should be used when formatting an error message for the generic
68/// type `Error`.
69///
70/// If `std` feature is OFF appends error source (delimited by `: `). We do this because
71/// `e.source()` is only available in std builds, without this macro the error source is lost for
72/// no-std builds.
73#[macro_export]
74macro_rules! write_err_unchecked_source {
75 ($writer:expr, $string:literal $(, $args:expr)*; $source:expr) => {
76 {
77 #[cfg(feature = "std")]
78 {
79 let _ = &$source; // Prevents clippy warnings.
80
81 write!($writer, $string $(, $args)*)
82 }
83 #[cfg(not(feature = "std"))]
84 {
85 write!($writer, concat!($string, ": {}") $(, $args)*, $source)
86 }
87 }
88 }
89}