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