kenzu 0.0.2

Procedural macros for builder pattern generation and validation
Documentation
use super::prelude::*;
use mokuya::components::prelude::*;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{DeriveInput, Field, Lit};

pub fn validator_range(input: &DeriveInput, field: &Field) -> TokenStream {
    let field_name = field.ident.as_ref().expect("field_name must be set");
    let attributes = get_attributes(input);
    let range = get_range(attributes);

    fn try_parse_literal(ts: &TokenStream) -> Option<Lit> {
        syn::parse2::<Lit>(ts.clone()).ok()
    }

    if let (Some(min_ts), Some(max_ts)) = (&range.min, &range.max) {
        if let (Some(min_lit), Some(max_lit)) =
            (try_parse_literal(min_ts), try_parse_literal(max_ts))
        {
            let min_val_opt = match &min_lit {
                Lit::Int(lit_int) => lit_int.base10_parse::<i128>().ok(),
                Lit::Float(lit_float) => lit_float.base10_parse::<f64>().ok().map(|f| f as i128),
                _ => None,
            };
            let max_val_opt = match &max_lit {
                Lit::Int(lit_int) => lit_int.base10_parse::<i128>().ok(),
                Lit::Float(lit_float) => lit_float.base10_parse::<f64>().ok().map(|f| f as i128),
                _ => None,
            };

            if let (Some(min_val), Some(max_val)) = (min_val_opt, max_val_opt) {
                if min_val > max_val {
                    return syn::Error::new_spanned(
                        field,
                        format!(
                            "invalid range: min ({}) cannot be greater than max ({})",
                            min_val, max_val
                        ),
                    )
                    .to_compile_error();
                }
            }
        }
    }

    let mut validation_code = TokenStream::new();

    if let Some(min_ts) = &range.min {
        if let Some(min_error) = &range.err_min {
            validation_code.extend(quote! {
                if self.#field_name < #min_ts {
                    return Err(#min_error);
                }
            });
        }
    }

    if let Some(max_ts) = &range.max {
        if let Some(max_error) = &range.err_max {
            validation_code.extend(quote! {
                if self.#field_name > #max_ts {
                    return Err(#max_error);
                }
            });
        }
    }

    validation_code
}