git_function_history_proc_macro/
lib.rs1use proc_macro::TokenStream;
2use proc_macro2::Span;
3use quote::{quote_spanned, ToTokens};
4use syn::{parse_macro_input, DeriveInput};
5
6#[proc_macro_derive(enumstuff, attributes(enumstuff))]
12pub fn enum_stuff(input: TokenStream) -> TokenStream {
13 let ast = parse_macro_input!(input as DeriveInput);
14 let span = Span::call_site();
15 let name = &ast.ident;
16 let vis = &ast.vis;
17 let data = match ast.data {
18 syn::Data::Enum(data) => data,
19 _ => panic!("Only enums are supported"),
20 };
21
22 let variants = data.variants.iter().map(|var| {
23 let name = var.ident.to_string();
24 quote_spanned!(span=>#name=>true,)
25 });
26
27 let types = data
28 .variants
29 .iter()
30 .filter_map(|v| {
31 for attr in &v.attrs {
33 if attr.path().is_ident("enumstuff") {
35 let p = attr.parse_args::<syn::Ident>().unwrap();
36 if p == "skip" {
37 return None;
38 }
39 }
40 }
41
42 let name_tok = v.ident.to_token_stream();
43 let name = name_tok.to_string();
44 Some(match v.fields.clone() {
45 syn::Fields::Named(_) => {
46 quote_spanned!(span=>#name => None,)
47 }
48 syn::Fields::Unnamed(v) => {
49 let values = v.unnamed;
50 let v = values
51 .iter()
52 .map(|v| {
53 let rest = quote_spanned!(span=>rest);
54 if v.ty.to_token_stream().to_string() == "String" {
56 quote_spanned!(span=>#rest.join(" "))
57 } else {
58 let ty = v.ty.to_token_stream();
59 quote_spanned!(span=>#ty::from_str(#rest)?)
60 }
61 })
62 .collect::<Vec<_>>();
63 quote_spanned!(span=>#name => Some(Self::#name_tok(#(#v),*)),)
64 }
65 syn::Fields::Unit => {
66 let ident = v.ident.to_token_stream();
67 quote_spanned!(span=>#name => Some(Self::#ident),)
68 }
69 })
70 })
71 .collect::<Vec<_>>();
72
73 let gen = quote_spanned! {
74 span=>
77 impl #name {
78 #vis fn from_str(makeup: &[&str]) -> Option<Self> {
80 let (variant, rest) = makeup.split_first()?;
81 match *variant {
82 #(#types)*
83 _ => None,
84 }
85 }
86
87 #vis fn has_variant(variant: &str) -> bool {
88 match variant {
89 #(#variants)*
90 _ => false,
91 }
92 }
93 }
94 };
95 gen.into()
96}