#![deny(clippy::dbg_macro)]
#![deny(unused_crate_dependencies)]
use proc_macro2::{Span, TokenStream};
use syn::spanned::Spanned;
mod types;
pub(crate) use self::types::{DeriveInput, fatality, split};
fn fatality_inner(
input: proc_macro2::TokenStream,
) -> syn::Result<proc_macro2::TokenStream> {
let input_span = input.span();
let DeriveInput {
attrs,
vis,
ident,
generics,
data,
} = syn::parse2(input)?;
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(())
};
match data {
syn::Data::Enum(data_enum) => {
bail_if_has_generics(&generics, generics.span())?;
fatality::enum_gen(DeriveInput {
attrs,
vis,
ident,
generics,
data: data_enum,
})
}
syn::Data::Struct(data_struct) => {
bail_if_has_generics(&generics, generics.span())?;
fatality::struct_gen(DeriveInput {
attrs,
vis,
ident,
generics,
data: data_struct,
})
}
syn::Data::Union(_) => Err(syn::Error::new(
input_span,
"Only `enum` and `struct` types are supported",
)),
}
}
fn derive_fatality2(
input: proc_macro2::TokenStream,
) -> proc_macro2::TokenStream {
let ts =
fatality_inner(input).unwrap_or_else(|e| -> proc_macro2::TokenStream {
let mut ts = proc_macro2::TokenStream::new();
ts.extend(e.to_compile_error());
ts
});
expander::Expander::new("fatality")
.add_comment(
"Generated by `#[derive(::fatality::Fatality)]`".to_owned(),
)
.dry(!cfg!(feature = "expand"))
.write_to_out_dir(ts)
.unwrap()
}
#[proc_macro_derive(Fatality, attributes(fatal))]
pub fn derive_fatality(
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let input = TokenStream::from(input);
let output: TokenStream = derive_fatality2(input);
proc_macro::TokenStream::from(output)
}
fn split_inner(
input: proc_macro2::TokenStream,
) -> syn::Result<proc_macro2::TokenStream> {
let input_span = input.span();
let DeriveInput {
attrs,
vis,
ident,
generics,
data,
} = syn::parse2(input)?;
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(())
};
match data {
syn::Data::Enum(data_enum) => {
bail_if_has_generics(&generics, generics.span())?;
split::enum_gen(DeriveInput {
attrs,
vis,
ident,
generics,
data: data_enum,
})
}
syn::Data::Struct(data_struct) => {
bail_if_has_generics(&generics, generics.span())?;
split::struct_gen(
input_span,
DeriveInput {
attrs,
vis,
ident,
generics,
data: data_struct,
},
)
}
syn::Data::Union(_) => Err(syn::Error::new(
input_span,
"Only `enum` and `struct` types are supported",
)),
}
}
fn derive_split2(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
let ts = split_inner(input.clone()).unwrap_or_else(
|e| -> proc_macro2::TokenStream {
let mut ts = proc_macro2::TokenStream::new();
ts.extend(e.to_compile_error());
ts
},
);
expander::Expander::new("split")
.add_comment("Generated by `#[derive(::fatality::Split)]`".to_owned())
.dry(!cfg!(feature = "expand"))
.write_to_out_dir(ts)
.unwrap()
}
#[proc_macro_derive(Split, attributes(split))]
pub fn derive_split(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = TokenStream::from(input);
let output: TokenStream = derive_split2(input);
proc_macro::TokenStream::from(output)
}
#[cfg(test)]
mod test;