1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#![deny(clippy::dbg_macro)]
#![deny(unused_crate_dependencies)]

use proc_macro2::{Span, TokenStream};
use syn::spanned::Spanned;

mod types;

pub(crate) use self::types::*;

fn fatality2_inner(
    attr: proc_macro2::TokenStream,
    input: proc_macro2::TokenStream,
) -> syn::Result<proc_macro2::TokenStream> {
    let bail_if_has_generics = |generics: &syn::Generics, span: Span| -> syn::Result<()> {
        if !generics.params.is_empty() {
            return Err(syn::Error::new(
                span,
                "Generics  `enum`-types are currently supported",
            ));
        }
        Ok(())
    };
    let attr = syn::parse2::<Attr>(attr)?;
    match syn::parse2::<syn::Item>(input.clone())? {
        syn::Item::Enum(item) => {
            bail_if_has_generics(&item.generics, item.span())?;
            fatality_enum_gen(attr, item)
        }
        syn::Item::Struct(item) => {
            bail_if_has_generics(&item.generics, item.span())?;
            fatality_struct_gen(attr, item)
        }
        other => Err(syn::Error::new(
            other.span(),
            "Only `enum` and `struct` types are supported",
        )),
    }
}

fn fatality2(
    attr: proc_macro2::TokenStream,
    input: proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
    let orig = input.clone();
    let ts = fatality2_inner(attr, input).unwrap_or_else(|e| -> proc_macro2::TokenStream {
        let mut ts = proc_macro2::TokenStream::new();
        ts.extend(orig);
        ts.extend(e.to_compile_error());
        ts
    });

    expander::Expander::new("fatality")
        .add_comment("Generated by `#[fatality::fatality]`".to_owned())
        // .fmt(expander::Edition::_2021)
        .dry(!cfg!(feature = "expand"))
        .write_to_out_dir(ts)
        .unwrap()
}

#[proc_macro_attribute]
pub fn fatality(
    attr: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let attr = TokenStream::from(attr);
    let input = TokenStream::from(input);

    let output: TokenStream = fatality2(attr, input);

    proc_macro::TokenStream::from(output)
}

#[cfg(test)]
mod tests;