newnum_proc_macros 0.13.1

Procedural macros reexported by the deprecated `newnum` crate
Documentation
use derive_syn_parse::Parse;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, Lit, Token};

pub fn num(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    num_macro_helper(
        "from_int_literal",
        "from_float_literal",
        quote! { ::newnum },
        input,
    )
}

pub fn num_approx(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    num_macro_helper(
        "approx_from_int_literal",
        "approx_from_float_literal",
        quote! { ::newnum },
        input,
    )
}

pub fn internal_num(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    num_macro_helper(
        "from_int_literal",
        "from_float_literal",
        quote! { crate },
        input,
    )
}

pub fn internal_num_approx(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    num_macro_helper(
        "approx_from_int_literal",
        "approx_from_float_literal",
        quote! { crate },
        input,
    )
}

fn num_macro_helper(
    int_fn_ident: &str,
    float_fn_ident: &str,
    crate_path: TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    #[derive(Parse)]
    struct Input {
        neg: Option<Token![-]>,
        literal: Lit,
        #[prefix(Option<Token![:]> as punct)]
        #[parse_if(punct.is_some())]
        ty: Option<TokenStream>,
    }

    let Input { neg, literal, ty } = parse_macro_input!(input as Input);

    let (literal_ty, from_trait, from_fn) = if let Lit::Float(_) = literal {
        (quote! { f64 }, quote! { FromFloatLiteral }, float_fn_ident)
    } else {
        (quote! { i128 }, quote! { FromIntLiteral }, int_fn_ident)
    };

    let from_fn = format_ident!("{from_fn}");
    let ty = ty.unwrap_or_else(|| quote! { _});

    quote! {
        {
            const MACRO_INPUT: #literal_ty = #neg #literal;

            {
                fn num_macro_fn<NumMacroType: #crate_path::#from_trait>() -> NumMacroType {
                    if const {
                        if MACRO_INPUT < <NumMacroType as #crate_path::FromIntLiteral>::MIN_LITERAL as #literal_ty {
                            panic!("literal out of range")
                        }

                        if MACRO_INPUT > <NumMacroType as #crate_path::FromIntLiteral>::MAX_LITERAL as #literal_ty {
                            panic!("literal out of range")
                        }

                        true
                    } {
                        unsafe { <NumMacroType as #crate_path::#from_trait>::#from_fn(MACRO_INPUT) }
                    } else {
                        unreachable!()
                    }
                }

                num_macro_fn::<#ty>()
            }
        }
    }
    .into()
}