padded_number_macros/
lib.rs1use proc_macro::TokenStream;
4use proc_macro2::TokenStream as TokenStream2;
5use quote::quote;
6use syn::{
7 LitInt, LitStr,
8 parse::{Parse, ParseStream},
9 parse_macro_input,
10 token::Comma,
11};
12
13#[proc_macro]
27pub fn padded_number(token_stream: TokenStream) -> TokenStream {
28 let number_literal = parse_macro_input!(token_stream as LitStr);
29
30 let args = Args { min: 1, max: u8::MAX, number_literal };
31
32 padded_number_impl(args).into()
33}
34
35#[proc_macro]
47pub fn bound_padded_number(token_stream: TokenStream) -> TokenStream {
48 let args = parse_macro_input!(token_stream as Args);
49 padded_number_impl(args).into()
50}
51
52struct Args {
53 min: u8,
54 max: u8,
55 number_literal: LitStr,
56}
57
58impl Parse for Args {
59 fn parse(input: ParseStream) -> syn::Result<Self> {
60 let min = input.parse::<LitInt>()?.base10_parse()?;
61 let _comma = input.parse::<Comma>()?;
62 let max = input.parse::<LitInt>()?.base10_parse()?;
63 let _comma = input.parse::<Comma>()?;
64 let number_string = input.parse::<LitStr>()?;
65
66 Ok(Args { min, max, number_literal: number_string })
67 }
68}
69
70fn padded_number_impl(args: Args) -> TokenStream2 {
71 let Args { min, max, number_literal } = args;
72 let number_str = number_literal.value();
73
74 match padded_number_internal::parse(min, max, &number_str) {
75 Ok((leading_zeros, remaining_number)) => {
76 quote! {
77 unsafe {
79 padded_number::PaddedNumber::<#min, #max>::new_unchecked(
80 #leading_zeros,
81 #remaining_number
82 )
83 }
84 }
85 }
86 Err(error) => syn::Error::new(number_literal.span(), error.to_string()).into_compile_error(),
87 }
88}