Skip to main content

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}