1mod app_error_impl;
18mod display;
19mod error_trait;
20mod from_impl;
21mod input;
22mod lint;
23mod masterror_impl;
24mod span;
25mod template_support;
26
27use proc_macro::TokenStream;
28use quote::quote;
29use syn::{Attribute, Data, DeriveInput, Error, parse_macro_input};
30
31#[proc_macro_derive(Error, attributes(error, source, from, backtrace, app_error, provide))]
32pub fn derive_error(tokens: TokenStream) -> TokenStream {
33 let input = parse_macro_input!(tokens as DeriveInput);
34 match expand(input) {
35 Ok(stream) => stream.into(),
36 Err(err) => err.to_compile_error().into()
37 }
38}
39
40#[proc_macro_derive(
41 Masterror,
42 attributes(error, source, from, backtrace, masterror, provide)
43)]
44pub fn derive_masterror(tokens: TokenStream) -> TokenStream {
45 let input = parse_macro_input!(tokens as DeriveInput);
46 match expand_masterror(input) {
47 Ok(stream) => stream.into(),
48 Err(err) => err.to_compile_error().into()
49 }
50}
51
52fn expand(input: DeriveInput) -> Result<proc_macro2::TokenStream, Error> {
53 let deprecated = references_deprecated(&input);
54 let parsed = input::parse_input(input)?;
55 let display_impl = display::expand(&parsed)?;
56 let error_impl = error_trait::expand(&parsed)?;
57 let from_impls = from_impl::expand(&parsed)?;
58 let app_error_impls = app_error_impl::expand(&parsed)?;
59 Ok(allow_deprecated(
60 deprecated,
61 quote! {
62 #display_impl
63 #error_impl
64 #(#from_impls)*
65 #(#app_error_impls)*
66 }
67 ))
68}
69
70fn expand_masterror(input: DeriveInput) -> Result<proc_macro2::TokenStream, Error> {
71 let deprecated = references_deprecated(&input);
72 let parsed = input::parse_input(input)?;
73 let display_impl = display::expand(&parsed)?;
74 let error_impl = error_trait::expand(&parsed)?;
75 let from_impls = from_impl::expand(&parsed)?;
76 let masterror_impl = masterror_impl::expand(&parsed)?;
77 Ok(allow_deprecated(
78 deprecated,
79 quote! {
80 #display_impl
81 #error_impl
82 #(#from_impls)*
83 #masterror_impl
84 }
85 ))
86}
87
88fn references_deprecated(input: &DeriveInput) -> bool {
94 fn has_deprecated(attrs: &[Attribute]) -> bool {
95 attrs.iter().any(|attr| attr.path().is_ident("deprecated"))
96 }
97 if has_deprecated(&input.attrs) {
98 return true;
99 }
100 match &input.data {
101 Data::Enum(data) => data
102 .variants
103 .iter()
104 .any(|variant| has_deprecated(&variant.attrs)),
105 _ => false
106 }
107}
108
109fn allow_deprecated(deprecated: bool, body: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
114 if deprecated {
115 quote! {
116 #[allow(deprecated)]
117 const _: () = {
118 #body
119 };
120 }
121 } else {
122 body
123 }
124}