tupleops-macros 0.1.0

Procedural macros needed to implement tupleops
Documentation
use proc_macro::TokenStream;
use syn::parse_macro_input::parse;
use syn::{Expr, ExprLit, ExprRange, Lit, RangeLimits};

fn get_usize(expr: &Option<Box<Expr>>) -> Result<usize, ()> {
    let expr = match expr {
        Some(expr) => expr.as_ref(),
        None => return Err(()),
    };
    let lit = match expr {
        Expr::Lit(ExprLit {
            lit: Lit::Int(lit), ..
        }) => lit,
        _ => return Err(()),
    };
    match lit.base10_parse() {
        Ok(value) => Ok(value),
        Err(_) => Err(()),
    }
}

fn parse_range(input: TokenStream) -> Result<(usize, usize), ()> {
    let range: ExprRange = match parse(input) {
        Ok(range) => range,
        Err(_) => return Err(()),
    };
    if !matches!(range.limits, RangeLimits::Closed(_)) {
        return Err(());
    }
    let from = match get_usize(&range.from) {
        Ok(from) => from,
        Err(_) => return Err(()),
    };
    let to = match get_usize(&range.to) {
        Ok(to) => to,
        Err(_) => return Err(()),
    };
    Ok((from, to))
}

pub(crate) fn generate(
    input: TokenStream,
    gen: fn(&mut String, usize, usize) -> Result<(), std::fmt::Error>,
) -> TokenStream {
    if let Ok((from, to)) = parse_range(input) {
        let mut code = String::new();
        if gen(&mut code, from, to).is_ok() {
            return code.parse().unwrap();
        }
    }
    r#"::core::compile_error("Expected closed range of usizes")"#
        .parse()
        .unwrap()
}