error_fatality_proc_macro/
lib.rs1#![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 .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 .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;