flex_error/macros.rs
1pub use paste::paste;
2
3/**
4 `define_error!` is the main macro that implements a mini DSL to
5 define error types using `flex-error`. The DSL syntax
6 is as follows:
7
8 ```ignore
9 define_error! {
10 ErrorName {
11 SubErrorWithFieldsAndErrorSource
12 { field1: Type1, field2: Type2, ... }
13 [ ErrorSource ]
14 | e | { format_args!(
15 "format error message with field1: {}, field2: {}, source: {}",
16 e.field1, e.field2, e.source)
17 },
18 SubErrorWithFieldsOnly
19 { field1: Type1, field2: Type2, ... }
20 | e | { format_args!(
21 "format error message with field1: {}, field2: {}",
22 e.field1, e.field2)
23 },
24 SubErrorWithSourceOnly
25 [ ErrorSource ]
26 | e | { format_args!(
27 "format error message with source: {}",
28 e.source)
29 },
30 SubError
31 | e | { format_args!(
32 "only suberror message")
33 },
34 }
35 }
36 ```
37
38 ## Macro Expansion
39
40 Behind the scene, for an error named `MyError`, `define_error!`
41 does the following:
42
43 - Define a struct in the form
44
45 ```ignore
46 pub struct MyError(pub MyErrorDetail, pub flex_error::DefaultTracer)
47 ```
48
49 - Define an enum in the form
50
51 ```ignore
52 pub enum MyError { ... }
53 ```
54
55 For each suberror named `MySubError`, does the following:
56
57 - Define a variant in `MyError` in the form
58 ```ignore
59 pub enum MyError { ..., MySubError(MySubErrorSubdetail) ,... }
60 ```
61
62 - Implement [`core::fmt::Debug`] and [`core::fmt::Display`]
63 for `MyError`.
64
65 - If the `"std"` feature is enabled on the `flex-error` crate,
66 it will generate an `impl` block for [`std::error::Error`].
67
68 - Implement [`ErrorSource<DefaultTracer>`](crate::ErrorSource)
69 for `MyError`, with `MyErrorDetail` being the `Detail` type,
70 and `MyError` being the `Source` type.
71
72 - Implement the following helper methods in `impl MyError {...}`:
73
74 - `pub fn detail(&self) -> &MyErrorDetail`
75
76 - `pub fn trace(&self) -> flex_error::DefaultTracer`
77
78 - `pub fn add_trace<E: Display>(self, e: &E) -> MyError`
79
80 - Define a struct in the form
81
82 ```ignore
83 pub struct MySubErrorSubdetail { ... }
84 ```
85
86 - For each field named `my_field: MyFieldType`, define a struct
87 field in the form
88
89 ```ignore
90 struct MySubErrorSubdetail { ..., pub my_field: MyFieldType, ... }
91 ```
92
93 - If the sub-error has an error source `MySource` implementing
94 [`ErrorSource<DefaultTracer>`](crate::ErrorSource), define a `source` field
95 in the form
96
97 ```ignore
98 struct MySubErrorSubdetail { ..., pub source: MySource::Detail }
99 ```
100
101 - Implement [`core::fmt::Display`] in the form
102
103 ```ignore
104 impl Display for MySubErrorSubdetail { ... }
105 ```
106
107 - Define a snake-cased error constructor method in `MyError` in the form
108
109 ```ignore
110 impl MyError { pub fn my_sub_error(...) -> MyError { ... } }
111 ```
112
113 - For each field named `my_field: MyFieldType`, define a
114 function argument in the form
115
116 ```ignore
117 fn my_sub_error(..., my_field: MyFieldType, ...)
118 ```
119
120 - If the sub-error has an error source `MySource` implementing
121 [`ErrorSource`](crate::ErrorSource), define a `source` field in the form
122
123 ```ignore
124 fn my_sub_error(..., source: MySource::Detail)
125 ```
126
127 ## Formatter
128
129 For each sub-error definition, a formatter needs to be provided using the
130 closure syntax. For example, the following definition:
131
132
133 ```ignore
134 MyError {
135 MySubError
136 { code: u32 }
137 [ MySource ]
138 | e | { format_args!("error with code {}", e.code) },
139 ...
140 }
141 ```
142
143 will include the following expansion:
144
145 ```
146 impl ::core::fmt::Display for MySubErrorSubdetail {
147 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
148 let e = self;
149 write!(f, "{}", format_args!("error with code {}", e.code))
150 }
151 }
152 ```
153
154 Note that there is no need to manually display the error source, as the
155 source is already automatically traced by the error tracer.
156
157 If a sub-error do not have any field, we can write a simpler form of the
158 formatter like:
159
160 ```ignore
161 MyError {
162 MySubError
163 | _ | { "something went wrong" },
164 ...
165 }
166 ```
167
168 ## Example Definition
169
170 We can demonstrate the macro expansion of `define_error!` with the following example:
171
172 ```ignore
173 // An external error type implementing Display
174 use external_crate::ExternalError;
175
176 define_error! {
177 FooError {
178 Bar
179 { code: u32 }
180 [ DisplayError<ExternalError> ]
181 | e | { format_args!("Bar error with code {}", e.code) },
182 Baz
183 { extra: String }
184 | e | { format_args!("General Baz error with extra detail: {}", e.extra) }
185 }
186 }
187 ```
188
189 The above code will be expanded into something like follows:
190
191 ```ignore
192 pub struct FooError(pub FooErrorDetail, pub flex_error::DefaultTracer);
193
194 #[derive(Debug)]
195 pub enum FooErrorDetail {
196 Bar(BarSubdetail),
197 Baz(BazSubdetail),
198 }
199
200 #[derive(Debug)]
201 pub struct BarSubdetail {
202 pub code: u32,
203 pub source: ExternalError
204 }
205
206 #[derive(Debug)]
207 pub struct BazSubdetail {
208 pub extra: String
209 }
210
211 fn bar_error(code: u32, source: ExternalError) -> FooError { ... }
212 fn baz_error(extra: String) -> FooError { ... }
213
214 impl ::core::fmt::Display for BarSubdetail {
215 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
216 let e = self;
217 write!(f, "{}", format_args!("Bar error with code {}", e.code))
218 }
219 }
220
221 impl ::core::fmt::Display for BazSubdetail {
222 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
223 let e = self;
224 write!(f, "{}", format_args!("General Baz error with extra detail: {}", e.code))
225 }
226 }
227
228 impl Display for FooErrorDetail { ... }
229 ```
230
231 For the detailed macro expansion, you can use [cargo-expand](https://github.com/dtolnay/cargo-expand)
232 to expand the Rust module that uses `define_error!` to see how the error definition
233 gets expanded.
234
235 Since `FooError` implements [`ErrorSource`](crate::ErrorSource), it can be used
236 directly as a error source in other error definitions. For example:
237
238 ```ignore
239 define_error! {
240 QuuxError {
241 Foo
242 { action: String }
243 [ FooError ]
244 | e | { format_args!("error arised from Foo when performing action {}", e.action) },
245 ...
246 }
247 }
248 ```
249
250 Would be expanded to include the following definitions:
251
252 ```ignore
253 pub struct FooSubdetail {
254 pub action: String,
255 pub source: FooErrorDetail
256 }
257
258 pub fn foo_error(action: String, source: FooError) { ... }
259 ```
260
261 In the formatter for `QuuxErrorDetail::Foo`, we can also see that it does not
262 need to include the error string from `FooError`. This is because the error
263 tracer already takes care of the source error trace, so the full trace is
264 automatically tracked inside `foo_error`. The outer error only need to
265 add additional detail about what caused the source error to be raised.
266
267 ## Attributes
268
269 `define_error!` supports adding attributes to the generated error types.
270
271 ### First `doc` Attribute
272
273 If the first attribute is a [`doc`](https://doc.rust-lang.org/rustdoc/the-doc-attribute.html)
274 attribute, it is attached to the main error struct. For example:
275
276 ```ignore
277 define_error! {
278 /// Documentation for MyError
279 MyError { ... }
280 }
281 ```
282
283 will include the following expansion:
284
285 ```ignore
286 #[doc = "Documentation for MyError"]
287 pub struct MyError(pub MyErrorDetail, pub flex_error::DefaultTracer);
288 ```
289
290 ## Common Attributes
291
292 For all other attributes defined on the main error type,
293 they are defined on the _error detail_ and _sub-errors type. For example:
294
295
296 ```ignore
297 define_error! {
298 #[derive(Debug, Clone)]
299 MyError {
300 Foo
301 { ... }
302 | _ | { "foo error" },
303
304 Bar
305 { ... }
306 | _ | { "bar error" },
307 }
308 }
309 ```
310
311 will include the following expansion:
312
313 ```ignore
314 pub struct MyError(pub MyErrorDetail, pub flex_error::DefaultTracer);
315
316 #[derive(Debug, Clone)]
317 pub enum MyErrorDetail { ... }
318
319 #[derive(Debug, Clone)]
320 pub struct FooSubdetail { ... }
321
322 #[derive(Debug, Clone)]
323 pub struct BarSubdetail { ... }
324 ```
325
326 Note that we do not add the `derive` attribute to the main error struct
327 `MyError`. This is because the [`DefaultTracer`](crate::DefaultTracer)
328 type is opaque, and auto deriving traits like `Clone` on it is
329 generally not supported.
330
331 If you need the main error type to implement certain traits,
332 you can instead define your own custom `impl` definition for it.
333
334 ## Sub Attributes
335
336 We can also define custom attributes for only the sub-error.
337 In that case, the attribute is given to the sub-detail type.
338 For example:
339
340 ```ignore
341 define_error! {
342 MyError {
343 /// Documentation for Foo
344 #[derive(Clone)]
345 Foo
346 { ... }
347 | _ | { "foo error" },
348
349 ...
350 }
351 }
352 ```
353
354 will include the following expansion:
355
356 ```ignore
357 #[doc = "Documentation for Foo"]
358 #[derive(Clone)]
359 pub struct FooSubdetail { ... }
360 ```
361
362 Note that if no attribute is given to the main error,
363 the `#[derive(Debug)]` trait is added by default.
364 So there is no need to derive it again in the
365 sub-errors.
366
367**/
368
369#[macro_export]
370macro_rules! define_error {
371 ( $name:ident
372 { $($suberrors:tt)* }
373 ) => {
374 $crate::define_error_with_tracer![
375 @tracer( $crate::DefaultTracer ),
376 @attr[ derive(Debug) ],
377 @name( $name ),
378 @suberrors{ $($suberrors)* }
379 ];
380 };
381 ( #[doc = $doc:literal] $( #[$attr:meta] )*
382 $name:ident
383 { $($suberrors:tt)* }
384 ) => {
385 $crate::define_error_with_tracer![
386 @tracer( $crate::DefaultTracer ),
387 @doc( $doc ),
388 @attr[ $( $attr ),* ],
389 @name( $name ),
390 @suberrors{ $($suberrors)* }
391 ];
392 };
393 ( $( #[$attr:meta] )*
394 $name:ident
395 { $($suberrors:tt)* }
396 ) => {
397 $crate::define_error_with_tracer![
398 @tracer( $crate::DefaultTracer ),
399 @attr[ $( $attr ),* ],
400 @name( $name ),
401 @suberrors{ $($suberrors)* }
402 ];
403 };
404 ( @with_tracer[ $tracer:ty ]
405 $name:ident,
406 { $($suberrors:tt)* }
407 ) => {
408 $crate::define_error_with_tracer![
409 @tracer( $tracer ),
410 @attr[ derive(Debug) ],
411 @name( $name ),
412 @suberrors{ $($suberrors)* }
413 ];
414 };
415 ( @with_tracer[ $tracer:ty ]
416 $( #[$attr:meta] )*
417 $name:ident,
418 @suberrors{ $($suberrors:tt)* }
419 ) => {
420 $crate::define_error_with_tracer![
421 @tracer( $tracer ),
422 @attr[ $( $attr ),* ],
423 @name( $name ),
424 @suberrors{ $($suberrors)* }
425 ];
426 };
427}
428
429/// This macro allows error types to be defined with custom error tracer types
430/// other than [`DefaultTracer`](crate::DefaultTracer). Behind the scene,
431/// a macro call to `define_error!{ ... } really expands to
432/// `define_error_with_tracer!{ flex_error::DefaultTracer; ... }`
433#[macro_export]
434#[doc(hidden)]
435macro_rules! define_error_with_tracer {
436 ( @tracer( $tracer:ty ),
437 $( @doc($doc:literal), )?
438 @attr[ $( $attr:meta ),* ],
439 @name($name:ident),
440 @suberrors{ $($suberrors:tt)* } $(,)?
441 ) => {
442 $crate::macros::paste![
443 $crate::define_main_error!(
444 @tracer( $tracer ),
445 $( @doc( $doc ), )?
446 @name( $name )
447 );
448
449 $crate::define_error_detail!(
450 @attr[ $( $attr ),* ] ,
451 @name( $name ),
452 @suberrors{ $($suberrors)* });
453
454 $crate::define_suberrors! {
455 @tracer($tracer),
456 @attr[ $( $attr ),* ],
457 @name($name),
458 { $( $suberrors )* }
459 }
460 ];
461 };
462}
463
464#[macro_export]
465#[doc(hidden)]
466macro_rules! define_main_error {
467 ( @tracer( $tracer:ty ),
468 $( @doc( $doc:literal ), )?
469 @name( $name:ident ) $(,)?
470 ) => {
471 $crate::macros::paste![
472 $crate::define_main_error_struct!(
473 @tracer( $tracer ),
474 $( @doc($doc), )?
475 @name( $name )
476 );
477
478 impl $crate::ErrorSource<$tracer> for $name {
479 type Source = Self;
480 type Detail = [< $name Detail >];
481
482 fn error_details($name(detail, trace): Self) -> ([< $name Detail >], Option<$tracer>) {
483 (detail, Some(trace))
484 }
485 }
486
487 impl ::core::fmt::Debug for $name
488 where
489 $tracer: ::core::fmt::Debug,
490 {
491 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
492 ::core::fmt::Debug::fmt(self.trace(), f)
493 }
494 }
495
496 impl ::core::fmt::Display for $name
497 where
498 $tracer: ::core::fmt::Debug,
499 {
500 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>)
501 -> ::core::fmt::Result
502 {
503 // Always use `Debug` to format error traces, as eyre do not
504 // include full back trace information in normal Display mode.
505 ::core::fmt::Debug::fmt(self.trace(), f)
506 }
507 }
508
509 $crate::define_std_err_impl!(
510 @tracer( $tracer ),
511 @name( $name )
512 );
513
514 impl $name {
515 pub fn detail(&self) -> &[< $name Detail >] {
516 &self.0
517 }
518
519
520 pub fn into_detail(self) -> [< $name Detail >] {
521 self.0
522 }
523
524 pub fn trace(&self) -> &$tracer {
525 &self.1
526 }
527
528 pub fn into_trace(self) -> $tracer {
529 self.1
530 }
531
532 pub fn add_trace<E: ::core::fmt::Display>(self, message: &E) -> Self
533 where
534 $tracer: $crate::ErrorMessageTracer,
535 {
536 let detail = self.0;
537 let trace = $crate::ErrorMessageTracer::add_message(self.1, message);
538 $name(detail, trace)
539 }
540
541 pub fn trace_from<E, Cont>(source: E::Source, cont: Cont) -> Self
542 where
543 E: $crate::ErrorSource<$tracer>,
544 $tracer: $crate::ErrorMessageTracer,
545 Cont: FnOnce(E::Detail) -> [< $name Detail >],
546 {
547 let (detail1, m_trace1) = E::error_details(source);
548 let detail2 = cont(detail1);
549 match m_trace1 {
550 Some(trace1) => {
551 let trace2 = $crate::ErrorMessageTracer::add_message(trace1, &detail2);
552 $name(detail2, trace2)
553 }
554 None => {
555 let trace2 = $crate::ErrorMessageTracer::new_message(&detail2);
556 $name(detail2, trace2)
557 }
558 }
559 }
560 }
561 ];
562 }
563}
564
565// define the impl for `std::error::Error` only in std mode
566#[cfg(feature = "std")]
567#[macro_export]
568#[doc(hidden)]
569macro_rules! define_std_err_impl {
570 ( @tracer( $tracer:ty ),
571 @name( $name:ident ) $(,)?
572 ) => {
573 $crate::macros::paste![
574 impl $crate::StdError for $name
575 where
576 [< $name Detail >]: ::core::fmt::Display,
577 $tracer: ::core::fmt::Debug + ::core::fmt::Display,
578 $tracer: $crate::ErrorMessageTracer,
579 {
580 fn source(&self) -> ::core::option::Option<&(dyn $crate::StdError + 'static)> {
581 $crate::ErrorMessageTracer::as_error(self.trace())
582 }
583 }
584 ];
585 }
586}
587
588// do not define the impl for `std::error::Error` when in no_std mode
589#[cfg(not(feature = "std"))]
590#[macro_export]
591#[doc(hidden)]
592macro_rules! define_std_err_impl {
593 ( @tracer( $tracer:ty ),
594 @name( $name:ident ) $(,)?
595 ) => {};
596}
597
598#[macro_export]
599#[doc(hidden)]
600macro_rules! define_main_error_struct {
601 ( @tracer( $tracer:ty ),
602 $( @doc( $doc:literal ), )?
603 @name( $name:ident ) $(,)?
604 ) => {
605 $crate::macros::paste![
606 $( #[doc = $doc] )?
607 pub struct $name (pub [< $name Detail >], pub $tracer);
608 ];
609 }
610}
611
612#[macro_export]
613#[doc(hidden)]
614macro_rules! with_suberrors {
615 ( @cont($cont:path),
616 @ctx[ $($args:tt)* ],
617 @suberrors{
618 $(
619 $( #[$sub_attr:meta] )*
620 $suberror:ident
621 $( { $( $arg_name:ident : $arg_type:ty ),* $(,)? } )?
622 $( [ $source:ty ] )?
623 | $formatter_arg:pat | $formatter:expr
624 ),* $(,)?
625 } $(,)?
626 ) => {
627 $cont!( @ctx[ $( $args )* ], @suberrors{ $( $suberror ),* } );
628 }
629}
630
631#[macro_export]
632#[doc(hidden)]
633macro_rules! define_error_detail {
634 ( @attr[ $( $attr:meta ),* ],
635 @name( $name:ident ),
636 @suberrors{ $($suberrors:tt)* } $(,)?
637 ) => {
638 $crate::with_suberrors!(
639 @cont($crate::define_error_detail_enum),
640 @ctx[
641 @attr[ $( $attr ),* ],
642 @name($name)
643 ],
644 @suberrors{ $( $suberrors )* }
645 );
646
647 $crate::with_suberrors!(
648 @cont($crate::define_error_detail_display),
649 @ctx[
650 @name($name)
651 ],
652 @suberrors{ $( $suberrors )* }
653 );
654 }
655}
656
657#[macro_export]
658#[doc(hidden)]
659macro_rules! define_error_detail_enum {
660 ( @ctx[
661 @attr[ $( $attr:meta ),* ],
662 @name($name:ident)
663 ],
664 @suberrors{ $( $suberror:ident ),* } $(,)?
665 ) => {
666 $crate::macros::paste! [
667 $( #[$attr] )*
668 pub enum [< $name Detail >] {
669 $(
670 $suberror (
671 [< $suberror Subdetail >]
672 )
673 ),*
674 }
675 ];
676 }
677}
678
679#[macro_export]
680#[doc(hidden)]
681macro_rules! define_error_detail_display {
682 ( @ctx[
683 @name( $name:ident )
684 ],
685 @suberrors{ $( $suberror:ident ),* } $(,)?
686 ) => {
687 $crate::macros::paste! [
688 impl ::core::fmt::Display for [< $name Detail >] {
689 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>)
690 -> ::core::fmt::Result
691 {
692 match self {
693 $(
694 Self::$suberror( suberror ) => {
695 ::core::write!( f, "{}", suberror )
696 }
697 ),*
698 }
699 }
700 }
701 ];
702 }
703}
704
705#[macro_export]
706#[doc(hidden)]
707macro_rules! define_suberrors {
708 ( @tracer($tracer:ty),
709 @attr[ $( $attr:meta ),* ],
710 @name($name:ident),
711 {} $(,)?
712 ) => { };
713 ( @tracer($tracer:ty),
714 @attr[ $( $attr:meta ),* ],
715 @name($name:ident),
716 {
717 $( #[$sub_attr:meta] )*
718 $suberror:ident
719 $( { $( $arg_name:ident : $arg_type:ty ),* $(,)? } )?
720 $( [ $source:ty ] )?
721 | $formatter_arg:pat | $formatter:expr
722
723 $( , $($tail:tt)* )?
724 }
725 ) => {
726 $crate::macros::paste![
727 $crate::define_suberror! {
728 @tracer( $tracer ),
729 @attr[ $( $attr ),* ],
730 @sub_attr[ $( $sub_attr ),* ],
731 @name( $name ),
732 @suberror( $suberror ),
733 @args( $( $( $arg_name : $arg_type ),* )? )
734 $( @source[ $source ] )?
735 }
736
737 impl ::core::fmt::Display for [< $suberror Subdetail >] {
738 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
739 use ::core::format_args;
740 let $formatter_arg = self;
741 ::core::write!(f, "{}", $formatter)
742 }
743 }
744
745 impl $name {
746 $crate::define_error_constructor! {
747 @tracer( $tracer ),
748 @name( $name ),
749 @suberror( $suberror ),
750 @args( $( $( $arg_name : $arg_type ),* )? )
751 $( @source[ $source ] )?
752 }
753 }
754 ];
755
756 $crate::define_suberrors! {
757 @tracer($tracer),
758 @attr[ $( $attr ),* ],
759 @name($name),
760 { $( $( $tail )* )? }
761 }
762 };
763}
764
765/// Internal macro used to define suberror structs
766#[macro_export]
767#[doc(hidden)]
768macro_rules! define_suberror {
769 ( @tracer( $tracer:ty ),
770 @attr[ $( $attr:meta ),* ],
771 @sub_attr[ $( $sub_attr:meta ),* ],
772 @name( $name:ident ),
773 @suberror( $suberror:ident ),
774 @args( $( $arg_name:ident: $arg_type:ty ),* )
775 @source[ Self ]
776 ) => {
777 $crate::macros::paste! [
778 $( #[ $attr ] )*
779 $( #[ $sub_attr ] )*
780 pub struct [< $suberror Subdetail >] {
781 $( pub $arg_name: $arg_type, )*
782 pub source: $crate::alloc::boxed::Box< [< $name Detail >] >
783 }
784 ];
785 };
786 ( @tracer( $tracer:ty ),
787 @attr[ $( $attr:meta ),* ],
788 @sub_attr[ $( $sub_attr:meta ),* ],
789 @name( $name:ident ),
790 @suberror( $suberror:ident ),
791 @args( $( $arg_name:ident: $arg_type:ty ),* )
792 $( @source[ $source:ty ] )?
793 ) => {
794 $crate::macros::paste! [
795 $( #[ $attr ] )*
796 $( #[ $sub_attr ] )*
797 pub struct [< $suberror Subdetail >] {
798 $( pub $arg_name: $arg_type, )*
799 $( pub source: $crate::AsErrorDetail<$source, $tracer> )?
800 }
801 ];
802 };
803}
804
805/// Internal macro used to define suberror constructor functions
806#[macro_export]
807#[doc(hidden)]
808macro_rules! define_error_constructor {
809 ( @tracer( $tracer:ty ),
810 @name( $name:ident ),
811 @suberror( $suberror:ident ),
812 @args( $( $arg_name:ident: $arg_type:ty ),* ) $(,)?
813 ) => {
814 $crate::macros::paste! [
815 pub fn [< $suberror:snake >](
816 $( $arg_name: $arg_type, )*
817 ) -> $name
818 {
819 let detail = [< $name Detail >]::$suberror([< $suberror Subdetail >] {
820 $( $arg_name, )*
821 });
822
823 let trace = < $tracer as $crate::ErrorMessageTracer >::new_message(&detail);
824 $name(detail, trace)
825 }
826 ];
827 };
828 ( @tracer( $tracer:ty ),
829 @name( $name:ident ),
830 @suberror( $suberror:ident ),
831 @args( $( $arg_name:ident: $arg_type:ty ),* )
832 @source[ Self ]
833 ) => {
834 $crate::macros::paste! [
835 pub fn [< $suberror:snake >](
836 $( $arg_name: $arg_type, )*
837 source: $name
838 ) -> $name
839 {
840 let detail = [< $name Detail >]::$suberror([< $suberror Subdetail >] {
841 $( $arg_name, )*
842 source: Box::new(source.0),
843 });
844
845 let trace = source.1.add_message(&detail);
846
847 $name(detail, trace)
848 }
849 ];
850 };
851 ( @tracer( $tracer:ty ),
852 @name( $name:ident ),
853 @suberror( $suberror:ident ),
854 @args( $( $arg_name:ident: $arg_type:ty ),* )
855 @source[ $source:ty ]
856 ) => {
857 $crate::macros::paste! [
858 pub fn [< $suberror:snake >](
859 $( $arg_name: $arg_type, )*
860 source: $crate::AsErrorSource< $source, $tracer >
861 ) -> $name
862 {
863 $name::trace_from::<$source, _>(source,
864 | source_detail | {
865 [< $name Detail >]::$suberror([< $suberror Subdetail >] {
866 $( $arg_name, )*
867 source: source_detail,
868 })
869 })
870 }
871 ];
872 };
873}