leo_errors/common/
macros.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17/// A macro that given an enum, exit code mask, error code string prefix,
18/// and error methods generated through a DSL creates and generates errors
19/// with a unique error code.
20#[macro_export]
21macro_rules! create_messages {
22    (@step $code:expr,) => {
23        #[inline(always)]
24        // Returns the number of unique exit codes that this error type can take on.
25        pub fn num_exit_codes() -> i32 {
26            $code
27        }
28    };
29    ($(#[$error_type_docs:meta])* $type_:ident, code_mask: $code_mask:expr, code_prefix: $code_prefix:expr, $($(#[$docs:meta])* @$formatted_or_backtraced_list:ident $names:ident { args: ($($arg_names:ident: $arg_types:ty$(,)?)*), msg: $messages:expr, help: $helps:expr, })*) => {
30        #[allow(unused_imports)] // Allow unused for errors that only use formatted or backtraced errors.
31        use $crate::{Backtraced, Formatted, LeoMessageCode};
32
33        use backtrace::Backtrace;
34
35        // Generates the enum and implements from FormattedError and BacktracedErrors.
36        #[derive(Clone, Debug, Error)]
37        $(#[$error_type_docs])*
38        pub enum $type_ {
39            #[error(transparent)]
40            Formatted(#[from] Formatted),
41
42	        #[error(transparent)]
43            Backtraced(#[from] Backtraced),
44        }
45
46        /// Implements the trait for LeoError Codes.
47        impl LeoMessageCode for $type_ {
48            #[inline(always)]
49            fn exit_code(&self) -> i32 {
50                match self {
51                    Self::Formatted(formatted) => formatted.exit_code(),
52                    Self::Backtraced(backtraced) => backtraced.exit_code()
53                }
54            }
55
56            #[inline(always)]
57            fn error_code(&self) -> String {
58                match self {
59                    Self::Formatted(formatted) => formatted.error_code(),
60                    Self::Backtraced(backtraced) => backtraced.error_code()
61                }
62            }
63
64            #[inline(always)]
65            fn warning_code(&self) -> String {
66                match self {
67                    Self::Formatted(formatted) => formatted.warning_code(),
68                    Self::Backtraced(backtraced) => backtraced.warning_code()
69                }
70            }
71
72            #[inline(always)]
73            fn code_mask() -> i32 {
74                $code_mask
75            }
76
77            #[inline(always)]
78            fn message_type() -> String {
79                $code_prefix.to_string()
80            }
81
82            #[inline(always)]
83            fn is_error() -> bool {
84                stringify!($type_).contains("Error")
85            }
86        }
87
88
89        // Steps over the list of functions with an initial code of 0.
90        impl $type_ {
91            create_messages!(@step 0i32, $(($(#[$docs])* $formatted_or_backtraced_list, $names($($arg_names: $arg_types,)*), $messages, $helps),)*);
92        }
93    };
94    // Matches the function if it is a formatted message.
95    (@step $code:expr, ($(#[$error_func_docs:meta])* formatted, $name:ident($($arg_names:ident: $arg_types:ty,)*), $message:expr, $help:expr), $(($(#[$docs:meta])* $formatted_or_backtraced_tail:ident, $names:ident($($tail_arg_names:ident: $tail_arg_types:ty,)*), $messages:expr, $helps:expr),)*) => {
96        // Formatted errors always takes a span.
97        $(#[$error_func_docs])*
98        // Expands additional arguments for the error defining function.
99        pub fn $name($($arg_names: $arg_types,)* span: leo_span::Span) -> Self {
100            Self::Formatted(
101                Formatted::new_from_span(
102                    $message,
103                    $help,
104                    $code + Self::code_mask(),
105                    Self::code_identifier(),
106                    Self::message_type(),
107                    Self::is_error(),
108                    span,
109                    // Each function always generates its own backtrace for backtrace clarity to originate from the error function.
110                    Backtrace::new(),
111                )
112            )
113        }
114
115        // Steps the code value by one and calls on the rest of the functions.
116        create_messages!(@step $code + 1i32, $(($(#[$docs])* $formatted_or_backtraced_tail, $names($($tail_arg_names: $tail_arg_types,)*), $messages, $helps),)*);
117    };
118    // matches the function if it is a backtraced message.
119    (@step $code:expr, ($(#[$error_func_docs:meta])* backtraced, $name:ident($($arg_names:ident: $arg_types:ty,)*), $message:expr, $help:expr), $(($(#[$docs:meta])* $formatted_or_backtraced_tail:ident, $names:ident($($tail_arg_names:ident: $tail_arg_types:ty,)*), $messages:expr, $helps:expr),)*) => {
120        $(#[$error_func_docs])*
121        // Expands additional arguments for the error defining function.
122        pub fn $name($($arg_names: $arg_types,)*) -> Self {
123            Self::Backtraced(
124                Backtraced::new_from_backtrace(
125                    $message,
126                    $help,
127                    $code + Self::code_mask(),
128                    Self::code_identifier(),
129                    Self::message_type(),
130                    Self::is_error(),
131                    // Each function always generates its own backtrace for backtrace clarity to originate from the error function.
132                    Backtrace::new(),
133                )
134            )
135        }
136
137        // Steps the code value by one and calls on the rest of the functions.
138        create_messages!(@step $code + 1i32, $(($(#[$docs])* $formatted_or_backtraced_tail, $names($($tail_arg_names: $tail_arg_types,)*), $messages, $helps),)*);
139    };
140}