Skip to main content

error_fatality_proc_macro/
lib.rs

1#![deny(clippy::dbg_macro)]
2#![deny(unused_crate_dependencies)]
3
4use proc_macro2::{Span, TokenStream};
5use syn::spanned::Spanned;
6
7mod types;
8
9pub(crate) use self::types::{DeriveInput, fatality, split};
10
11fn fatality_inner(
12    input: proc_macro2::TokenStream,
13) -> syn::Result<proc_macro2::TokenStream> {
14    let input_span = input.span();
15    let DeriveInput {
16        attrs,
17        vis,
18        ident,
19        generics,
20        data,
21    } = syn::parse2(input)?;
22    let bail_if_has_generics =
23        |generics: &syn::Generics, span: Span| -> syn::Result<()> {
24            if !generics.params.is_empty() {
25                return Err(syn::Error::new(
26                    span,
27                    "Generics  `enum`-types are currently supported",
28                ));
29            }
30            Ok(())
31        };
32    match data {
33        syn::Data::Enum(data_enum) => {
34            bail_if_has_generics(&generics, generics.span())?;
35            fatality::enum_gen(DeriveInput {
36                attrs,
37                vis,
38                ident,
39                generics,
40                data: data_enum,
41            })
42        }
43        syn::Data::Struct(data_struct) => {
44            bail_if_has_generics(&generics, generics.span())?;
45            fatality::struct_gen(DeriveInput {
46                attrs,
47                vis,
48                ident,
49                generics,
50                data: data_struct,
51            })
52        }
53        syn::Data::Union(_) => Err(syn::Error::new(
54            input_span,
55            "Only `enum` and `struct` types are supported",
56        )),
57    }
58}
59
60fn derive_fatality2(
61    input: proc_macro2::TokenStream,
62) -> proc_macro2::TokenStream {
63    let ts =
64        fatality_inner(input).unwrap_or_else(|e| -> proc_macro2::TokenStream {
65            let mut ts = proc_macro2::TokenStream::new();
66            ts.extend(e.to_compile_error());
67            ts
68        });
69
70    expander::Expander::new("fatality")
71        .add_comment(
72            "Generated by `#[derive(::fatality::Fatality)]`".to_owned(),
73        )
74        // .fmt(expander::Edition::_2021)
75        .dry(!cfg!(feature = "expand"))
76        .write_to_out_dir(ts)
77        .unwrap()
78}
79
80#[proc_macro_derive(Fatality, attributes(fatal))]
81pub fn derive_fatality(
82    input: proc_macro::TokenStream,
83) -> proc_macro::TokenStream {
84    let input = TokenStream::from(input);
85    let output: TokenStream = derive_fatality2(input);
86    proc_macro::TokenStream::from(output)
87}
88
89fn split_inner(
90    input: proc_macro2::TokenStream,
91) -> syn::Result<proc_macro2::TokenStream> {
92    let input_span = input.span();
93    let DeriveInput {
94        attrs,
95        vis,
96        ident,
97        generics,
98        data,
99    } = syn::parse2(input)?;
100    let bail_if_has_generics =
101        |generics: &syn::Generics, span: Span| -> syn::Result<()> {
102            if !generics.params.is_empty() {
103                return Err(syn::Error::new(
104                    span,
105                    "Generics  `enum`-types are currently supported",
106                ));
107            }
108            Ok(())
109        };
110    match data {
111        syn::Data::Enum(data_enum) => {
112            bail_if_has_generics(&generics, generics.span())?;
113            split::enum_gen(DeriveInput {
114                attrs,
115                vis,
116                ident,
117                generics,
118                data: data_enum,
119            })
120        }
121        syn::Data::Struct(data_struct) => {
122            bail_if_has_generics(&generics, generics.span())?;
123            split::struct_gen(
124                input_span,
125                DeriveInput {
126                    attrs,
127                    vis,
128                    ident,
129                    generics,
130                    data: data_struct,
131                },
132            )
133        }
134        syn::Data::Union(_) => Err(syn::Error::new(
135            input_span,
136            "Only `enum` and `struct` types are supported",
137        )),
138    }
139}
140
141fn derive_split2(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
142    let ts = split_inner(input.clone()).unwrap_or_else(
143        |e| -> proc_macro2::TokenStream {
144            let mut ts = proc_macro2::TokenStream::new();
145            ts.extend(e.to_compile_error());
146            ts
147        },
148    );
149
150    expander::Expander::new("split")
151        .add_comment("Generated by `#[derive(::fatality::Split)]`".to_owned())
152        // .fmt(expander::Edition::_2021)
153        .dry(!cfg!(feature = "expand"))
154        .write_to_out_dir(ts)
155        .unwrap()
156}
157
158#[proc_macro_derive(Split, attributes(split))]
159pub fn derive_split(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
160    let input = TokenStream::from(input);
161    let output: TokenStream = derive_split2(input);
162    proc_macro::TokenStream::from(output)
163}
164
165#[cfg(test)]
166mod test;