Skip to main content

formatted_index_macro/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Data, DeriveInput};
4
5#[proc_macro_derive(FormattedIndex)]
6pub fn formatted_index_derive(input: TokenStream) -> TokenStream {
7    // Parse the input tokens into a syntax tree
8    let input = parse_macro_input!(input as DeriveInput);
9
10    // Get the name of the enum
11    let name = &input.ident;
12
13    // Only work with enums
14    let data_enum = match input.data {
15        Data::Enum(data_enum) => data_enum,
16        _ => {
17            return quote! {
18                compile_error!("FormattedIndex can only be derived for enums");
19            }
20            .into()
21        }
22    };
23
24    // Generate match arms for each variant
25    let variants = data_enum.variants.iter().enumerate().map(|(i, variant)| {
26        let variant_name = &variant.ident;
27        // Convert to 1-based index
28        let one_based_index = i + 1;
29        let formatted_index = format!("[{one_based_index}]");
30
31        quote! {
32            #name::#variant_name { .. } => #formatted_index,
33        }
34    });
35
36    // Generate the implementation
37    let expanded = quote! {
38        impl #name {
39            /// Returns the variant's formatted index.
40            pub const fn to_formatted_index(&self) -> &'static str {
41                match self {
42                    #(#variants)*
43                }
44            }
45        }
46    };
47
48    TokenStream::from(expanded)
49}