1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use proc_macro2::Span;
5
6use quote::quote;
7use syn::{parse_macro_input, Data, DeriveInput, Error};
8
9macro_rules! derive_error {
10 ($string: tt) => {
11 Error::new(Span::call_site(), $string)
12 .to_compile_error()
13 .into()
14 };
15}
16
17fn parse_enum_doc_comment(attrs: &[syn::Attribute]) -> String {
18 let mut ret = String::new();
19 for attr in attrs {
20 let meta = &attr.meta;
21 if let syn::Meta::NameValue(meta) = meta {
22 if let syn::Expr::Lit(syn::ExprLit {
23 lit: syn::Lit::Str(l),
24 ..
25 }) = &meta.value
26 {
27 ret.push_str(&format!("\n {}", l.value().trim()));
28 }
29 }
30 }
31
32 ret
33}
34
35#[proc_macro_derive(EnumDocs)]
36pub fn derive_enum_docs(input: TokenStream) -> TokenStream {
52 let input: DeriveInput = parse_macro_input!(input);
53
54 match &input.data {
55 Data::Enum(data_enum) => {
57 let mut names = String::new();
61
62 for variant in &data_enum.variants {
64 let doc = parse_enum_doc_comment(&variant.attrs);
65
66 names.push_str(&format!("\n{}{}", variant.ident, doc));
67 }
68
69 let name = &input.ident;
71 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
72 quote! {
73 impl #impl_generics #name #ty_generics #where_clause {
74 pub const fn documentation() -> &'static str {
75 #names
76 }
77 }
78 }
79 .into()
80 }
81 _ => derive_error!("EnumDocs can only be implemented for enums"),
82 }
83}