burbomath_macro 0.0.1

Macro crate for burbokop's rust math library
Documentation
#![deny(warnings)]

use litrs::Literal;
use proc_macro::TokenStream;
use quote::quote;

fn validate_numeric_literal(
    input: TokenStream,
    predicate: fn(&Literal<String>) -> Result<(), TokenStream>,
) -> Result<(), TokenStream> {
    let input = input.into_iter().collect::<Vec<_>>();
    if input.len() != 1 {
        let msg = format!(
            "expected exactly one input token, but found {}",
            input.len()
        );
        return Err(quote! { compile_error!(#msg) }.into());
    }

    let lit = match Literal::try_from(&input[0]) {
        Ok(lit) => lit,
        Err(e) => return Err(e.to_compile_error()),
    };

    match lit {
        Literal::Integer(_) | Literal::Float(_) => predicate(&lit),
        _ => {
            let msg = format!("expected integer or float literal, but found {}", lit);
            Err(quote! { compile_error!(#msg) }.into())
        }
    }
}

fn must_be_positive(lit: &Literal<String>) -> Result<(), TokenStream> {
    match lit {
        Literal::Integer(lit) => {
            println!("int lit: {}", lit);
            if lit.value::<u128>().unwrap() == 0 {
                let msg = format!("expected positive number, but found {}", lit);
                return Err(quote! { compile_error!(#msg) }.into());
            }
        }
        Literal::Float(lit) => {
            println!("float lit: {}", lit);
            if lit.raw_input().parse::<f64>().unwrap() == 0. {
                let msg = format!("expected positive number, but found {}", lit);
                return Err(quote! { compile_error!(#msg) }.into());
            }
        }
        _ => unreachable!(),
    };
    Ok(())
}

#[proc_macro]
pub fn non_neg(input: TokenStream) -> TokenStream {
    let input2: proc_macro2::TokenStream = input.clone().into();

    if let Err(err) = validate_numeric_literal(input, |_| Ok(())) {
        return err;
    }

    quote! {
        unsafe { burbomath::NonNeg::new_const_unchecked(#input2) }
    }
    .into()
}

#[proc_macro]
pub fn positive(input: TokenStream) -> TokenStream {
    let input2: proc_macro2::TokenStream = input.clone().into();

    if let Err(err) = validate_numeric_literal(input, must_be_positive) {
        return err;
    }

    quote! {
        unsafe { burbomath::Positive::new_const_unchecked(#input2) }
    }
    .into()
}