error_tools/error.rs
1/// Internal namespace.
2mod private
3{
4 pub use std::error::Error as ErrorTrait;
5
6 /// This trait allows adding extra context or information to an error, creating a tuple of the additional
7 /// context and the original error. This is particularly useful for error handling when you want to include
8 /// more details in the error without losing the original error value.
9 ///
10 /// The `ErrWith` trait provides methods to wrap an error with additional context, either by using a closure
11 /// that generates the context or by directly providing the context.
12 ///
13 /// ```
14 pub trait ErrWith< ReportErr, ReportOk, E >
15 {
16 /// Takes a closure `f` that returns a value of type `ReportErr`, and uses it to wrap an error of type `(ReportErr, E)`
17 /// in the context of a `Result` of type `ReportOk`.
18 ///
19 /// This method allows you to add additional context to an error by providing a closure that generates the context.
20 ///
21 /// # Arguments
22 ///
23 /// * `f` - A closure that returns the additional context of type `ReportErr`.
24 ///
25 /// # Returns
26 ///
27 /// A `Result` of type `ReportOk` if the original result is `Ok`, or a tuple `(ReportErr, E)` containing the additional
28 /// context and the original error if the original result is `Err`.
29 ///
30 /// # Example
31 ///
32 /// ```rust
33 /// use error_tools::ErrWith;
34 /// let result : Result< (), std::io::Error > = Err( std::io::Error::new( std::io::ErrorKind::Other, "an error occurred" ) );
35 /// let result_with_context : Result< (), ( &str, std::io::Error ) > = result.err_with( || "additional context" );
36 /// ```
37 fn err_with< F >( self, f : F ) -> std::result::Result< ReportOk, ( ReportErr, E ) >
38 where
39 F : FnOnce() -> ReportErr;
40
41 /// Takes a reference to a `ReportErr` value and uses it to wrap an error of type `(ReportErr, E)`
42 /// in the context of a `Result` of type `ReportOk`.
43 ///
44 /// This method allows you to add additional context to an error by providing a reference to the context.
45 ///
46 /// # Arguments
47 ///
48 /// * `report` - A reference to the additional context of type `ReportErr`.
49 ///
50 /// # Returns
51 ///
52 /// A `Result` of type `ReportOk` if the original result is `Ok`, or a tuple `(ReportErr, E)` containing the additional
53 /// context and the original error if the original result is `Err`.
54 ///
55 /// # Example
56 ///
57 /// ```rust
58 /// use error_tools::ErrWith;
59 /// let result : Result< (), std::io::Error > = Err( std::io::Error::new( std::io::ErrorKind::Other, "an error occurred" ) );
60 /// let report = "additional context";
61 /// let result_with_report : Result< (), ( &str, std::io::Error ) > = result.err_with_report( &report );
62 /// ```
63 fn err_with_report( self, report : &ReportErr ) -> std::result::Result< ReportOk, ( ReportErr, E ) >
64 where
65 ReportErr : Clone;
66
67 }
68
69 impl< ReportErr, ReportOk, E, IntoError > ErrWith< ReportErr, ReportOk, E >
70 for std::result::Result< ReportOk, IntoError >
71 where
72 IntoError : Into< E >,
73 {
74
75 fn err_with< F >( self, f : F ) -> std::result::Result< ReportOk, ( ReportErr, E ) >
76 where
77 F : FnOnce() -> ReportErr,
78 {
79 self.map_err( | e | ( f(), e.into() ) )
80 }
81
82 #[ inline( always ) ]
83 fn err_with_report( self, report : &ReportErr ) -> std::result::Result< ReportOk, ( ReportErr, E ) >
84 where
85 ReportErr : Clone,
86 Self : Sized,
87 {
88 self.map_err( | e | ( report.clone(), e.into() ) )
89 }
90
91 }
92
93 /// A type alias for a `Result` that contains an error which is a tuple of a report and an original error.
94 ///
95 /// This is useful when you want to report additional information along with an error. The `ResultWithReport` type
96 /// helps in defining such results more concisely.
97 pub type ResultWithReport< Report, Error > = Result< Report, ( Report, Error ) >;
98
99 ///
100 /// Macro to generate an error descriptor.
101 ///
102 /// ### Basic use-case.
103 /// ```rust
104 /// # use error_tools::{ BasicError, err };
105 /// fn f1() -> BasicError
106 /// {
107 /// return err!( "No attr" );
108 /// }
109 /// ```
110 ///
111
112 #[ macro_export ]
113 macro_rules! err
114 {
115
116 ( $msg : expr ) =>
117 {
118 $crate::BasicError::new( $msg ).into()
119 };
120 ( $msg : expr, $( $arg : expr ),+ $(,)? ) =>
121 {
122 $crate::BasicError::new( format!( $msg, $( $arg ),+ ) ).into()
123 };
124
125 }
126
127 ///
128 /// Macro to return an Err( error ) generating error descriptor.
129 ///
130 /// ### Basic use-case.
131 /// ```rust
132 /// # use error_tools::{ BasicError, return_err };
133 /// fn f1() -> Result< (), BasicError >
134 /// {
135 /// return_err!( "No attr" );
136 /// }
137 /// ```
138 ///
139
140 #[ macro_export ]
141 macro_rules! return_err
142 {
143
144 ( $msg : expr ) =>
145 {
146 return Result::Err( $crate::err!( $msg ) )
147 };
148 ( $msg : expr, $( $arg : expr ),+ $(,)? ) =>
149 {
150 return Result::Err( $crate::err!( $msg, $( $arg ),+ ) )
151 };
152
153 }
154
155 // zzz : review
156
157 /// baic implementation of generic BasicError
158
159 #[ derive( core::fmt::Debug, core::clone::Clone, core::cmp::PartialEq, core::cmp::Eq ) ]
160 pub struct BasicError
161 {
162 msg : String,
163 }
164
165 impl BasicError
166 {
167 /// Constructor expecting message with description.
168 pub fn new< Msg : Into< String > >( msg : Msg ) -> BasicError
169 {
170 BasicError { msg : msg.into() }
171 }
172 /// Message with description getter.
173 pub fn msg( &self ) -> &String
174 {
175 &self.msg
176 }
177 }
178
179 impl core::fmt::Display for BasicError
180 {
181 fn fmt(&self, f: &mut core::fmt::Formatter< '_ >) -> core::fmt::Result
182 {
183 write!( f, "{}", self.msg )
184 }
185 }
186
187 impl ErrorTrait for BasicError
188 {
189 fn description( &self ) -> &str
190 {
191 &self.msg
192 }
193 }
194
195 impl< T > From< BasicError > for Result< T, BasicError >
196 {
197 /// Returns the argument unchanged.
198 #[ inline( always ) ]
199 fn from( src : BasicError ) -> Self
200 {
201 Result::Err( src )
202 }
203 }
204
205 pub use err;
206 pub use return_err;
207
208 // qqq : write standard mod interface without using mod_interface /* aaa : Dmytro : added to each library file */
209}
210
211#[ doc( inline ) ]
212#[ allow( unused_imports ) ]
213pub use own::*;
214
215/// Own namespace of the module.
216#[ allow( unused_imports ) ]
217pub mod own
218{
219 use super::*;
220 #[ doc( inline ) ]
221 pub use orphan::*;
222}
223
224/// Shared with parent namespace of the module
225#[ allow( unused_imports ) ]
226pub mod orphan
227{
228 use super::*;
229 #[ doc( inline ) ]
230 pub use exposed::*;
231}
232
233/// Exposed namespace of the module.
234#[ allow( unused_imports ) ]
235pub mod exposed
236{
237 use super::*;
238
239 #[ doc( inline ) ]
240 pub use private::
241 {
242 ErrWith,
243 ResultWithReport,
244 };
245
246 #[ doc( inline ) ]
247 pub use prelude::*;
248}
249
250/// Prelude to use essentials: `use my_module::prelude::*`.
251#[ allow( unused_imports ) ]
252pub mod prelude
253{
254 use super::*;
255
256 #[ doc( inline ) ]
257 pub use private::
258 {
259 err,
260 return_err,
261 ErrorTrait,
262 BasicError,
263 };
264
265}