api_code_macros/
lib.rs

1use proc_macro::TokenStream;
2use proc_macro2::Literal;
3use quote::quote;
4use syn::{Ident, LitInt, Token, parse_macro_input};
5
6#[proc_macro]
7pub fn enum_segment(input: TokenStream) -> TokenStream {
8    let input = parse_macro_input!(input as EnumSegmentInput);
9
10    let name = input.name;
11    let repr_type = input.repr_type;
12    let start = input.start;
13    let end = input.end;
14    let prefix = input.prefix;
15    let width = input.width;
16
17    let mut variants = Vec::new();
18
19    for i in start..=end {
20        let variant_name = format!("{prefix}{:0width$}", i, width = width as usize);
21        let variant_ident = Ident::new(&variant_name, name.span());
22        let variant_value = Literal::i32_unsuffixed(i);
23
24        variants.push(quote! {
25            #[allow(non_camel_case_types)]
26            #variant_ident = #variant_value,
27        });
28    }
29
30    let expanded = quote! {
31        #[allow(non_camel_case_types)]
32        #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
33        #[derive(num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
34        #[repr(#repr_type)]
35        #[non_exhaustive]
36        pub enum #name {
37            #(#variants)*
38        }
39        impl std::fmt::Display for #name {
40            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41                write!(f, "{:0>width$}", #repr_type::from(*self), width = #width as usize)
42            }
43        }
44    };
45
46    TokenStream::from(expanded)
47}
48
49struct EnumSegmentInput {
50    name: Ident,
51    repr_type: Ident,
52    start: i32,
53    end: i32,
54    prefix: String,
55    width: u32,
56}
57
58impl syn::parse::Parse for EnumSegmentInput {
59    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
60        let name: Ident = input.parse()?;
61        input.parse::<Token![,]>()?;
62
63        let repr_type: Ident = input.parse()?;
64        input.parse::<Token![,]>()?;
65
66        let start: LitInt = input.parse()?;
67        input.parse::<Token![,]>()?;
68
69        let end: LitInt = input.parse()?;
70        input.parse::<Token![,]>()?;
71
72        let prefix: Ident = input.parse()?;
73        input.parse::<Token![,]>()?;
74
75        let width: LitInt = input.parse()?;
76
77        Ok(EnumSegmentInput {
78            name,
79            repr_type,
80            start: start.base10_parse::<i32>()?,
81            end: end.base10_parse::<i32>()?,
82            prefix: prefix.to_string(),
83            width: width.base10_parse::<u32>()?,
84        })
85    }
86}