from_proc 0.1.2

A procedural macro for `from` crate
Documentation
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::Ident;

use crate::{
    metas_holder::MetasHolder,
    types::ints::{Ints, Processing, TooLargeErr, TooSmallErr},
    NullHandling, TypeMismatchErr,
};

impl super::ElemParsing {
    pub fn try_build_int<H, I>(
        vec_var: &Ident,
        idx_var: TokenStream2,
        metas_holder: Option<H>,
        dflt_lang: &str,
        null: bool,
    ) -> Result<Self, TokenStream>
    where
        I: Ints,
        H: MetasHolder,
    {
        match null {
            true => Self::try_build_int_null::<H, I>(vec_var, idx_var, metas_holder, dflt_lang),

            false => {
                Self::try_build_int_not_null::<H, I>(vec_var, idx_var, metas_holder, dflt_lang)
            }
        }
    }

    #[inline]
    fn try_build_int_null<H, I>(
        vec_var: &Ident,
        idx_var: TokenStream2,
        metas_holder: Option<H>,
        dflt_lang: &str,
    ) -> Result<Self, TokenStream>
    where
        I: Ints,
        H: MetasHolder,
    {
        let type_mismatch_err;
        let processing;
        let too_large_err;
        let too_small_err;

        let expc = I::expc();

        match metas_holder {
            Some(metas_holder) => {
                processing = Processing::try_build::<H, I>(&metas_holder, &idx_var, dflt_lang)?;

                type_mismatch_err =
                    TypeMismatchErr::try_build(&metas_holder, &idx_var, &dflt_lang, expc)?;

                too_large_err = TooLargeErr::try_build(&metas_holder, &idx_var, dflt_lang)?;

                too_small_err = TooSmallErr::try_build(&metas_holder, &idx_var, dflt_lang)?;
            }

            None => {
                processing = Processing::new();

                let msg = format!("expected: {}, found: {{}}", expc);
                type_mismatch_err =
                    TypeMismatchErr::new_dflt(&idx_var, quote! {format!(#msg, found)});

                too_large_err = TooLargeErr::new_dflt(&idx_var);

                too_small_err = TooSmallErr::new_dflt(&idx_var);
            }
        };

        let ty = I::ty();

        let null_handling =
            NullHandling::from_one(quote! {#vec_var.push(::from::Null::<#ty>::Null);});

        let elem_push = quote! {#vec_var.push(::from::Null::<#ty>::Some(val));};

        Ok(Self::build_int(
            ty,
            processing,
            elem_push,
            null_handling,
            type_mismatch_err,
            too_large_err,
            too_small_err,
        ))
    }

    #[inline]
    fn try_build_int_not_null<H, I>(
        vec_var: &Ident,
        idx_var: TokenStream2,
        metas_holder: Option<H>,
        dflt_lang: &str,
    ) -> Result<Self, TokenStream>
    where
        I: Ints,
        H: MetasHolder,
    {
        let type_mismatch_err;
        let processing;
        let null_handling;
        let too_large_err;
        let too_small_err;

        let expc = I::expc();

        let null_msg = format!("expected: {}, found: null", expc);

        match metas_holder {
            Some(metas_holder) => {
                processing = Processing::try_build::<H, I>(&metas_holder, &idx_var, dflt_lang)?;

                null_handling = NullHandling::try_build(
                    &metas_holder,
                    &idx_var,
                    &dflt_lang,
                    || -> TokenStream2 {
                        quote! {String::from(#null_msg)}
                    },
                )?;

                type_mismatch_err =
                    TypeMismatchErr::try_build(&metas_holder, &idx_var, &dflt_lang, &expc)?;

                too_large_err = TooLargeErr::try_build(&metas_holder, &idx_var, dflt_lang)?;

                too_small_err = TooSmallErr::try_build(&metas_holder, &idx_var, dflt_lang)?;
            }

            None => {
                processing = Processing::new();

                null_handling = NullHandling::new_dflt(&idx_var, quote! {String::from(#null_msg)});

                let msg = format!("expected: {}, found: {{}}", expc);

                type_mismatch_err =
                    TypeMismatchErr::new_dflt(&idx_var, quote! {format!(#msg, found)});

                too_large_err = TooLargeErr::new_dflt(&idx_var);

                too_small_err = TooSmallErr::new_dflt(&idx_var);
            }
        };

        Ok(Self::build_int(
            I::ty(),
            processing,
            quote! {#vec_var.push(val);},
            null_handling,
            type_mismatch_err,
            too_large_err,
            too_small_err,
        ))
    }

    #[inline]
    fn build_int(
        parser_module: TokenStream2,
        processing: Processing,
        elem_push: TokenStream2,
        null_handling: NullHandling,
        type_mismatch_err: TypeMismatchErr,
        too_large_err: TooLargeErr,
        too_small_err: TooSmallErr,
    ) -> Self {
        Self {
            none: int_field_match_parse_temp(
                &parser_module,
                processing.valdg,
                &elem_push,
                null_handling.none,
                type_mismatch_err.none,
                too_large_err.none,
                too_small_err.none,
            ),

            lang: int_field_match_parse_temp(
                &parser_module,
                processing.valdg_lang,
                &elem_push,
                null_handling.lang,
                type_mismatch_err.lang,
                too_large_err.lang,
                too_small_err.lang,
            ),

            stack_errs: int_field_match_parse_temp(
                &parser_module,
                processing.valdg_stack_errs,
                &elem_push,
                null_handling.stack_errs,
                type_mismatch_err.stack_errs,
                too_large_err.stack_errs,
                too_small_err.stack_errs,
            ),

            stack_errs_lang: int_field_match_parse_temp(
                &parser_module,
                processing.valdg_stack_errs_lang,
                &elem_push,
                null_handling.stack_errs_lang,
                type_mismatch_err.stack_errs_lang,
                too_large_err.stack_errs_lang,
                too_small_err.stack_errs_lang,
            ),
        }
    }
}

#[inline]
fn int_field_match_parse_temp(
    parser_module: &TokenStream2,
    valdg: TokenStream2,
    elem_push: &TokenStream2,
    null_handling: TokenStream2,
    type_mismatch_err: TokenStream2,
    too_large_err: TokenStream2,
    too_small_err: TokenStream2,
) -> TokenStream2 {
    quote! {
        match ::from::json::#parser_module::parse(json, idx) {
            ::from::json::#parser_module::ParseResult::Ok(val) => {
                #valdg
                #elem_push
            }

            ::from::json::#parser_module::ParseResult::Null => {
                #null_handling
            }


            ::from::json::#parser_module::ParseResult::TypeMismatch(found) => {
                #type_mismatch_err
            }

            ::from::json::#parser_module::ParseResult::TooLargeToFitInto(typ) => {
                #too_large_err
            }

            ::from::json::#parser_module::ParseResult::TooSmallToFitInto(typ) => {
                #too_small_err
            }

            ::from::json::#parser_module::ParseResult::SyntaxErr(e) => return Err(From::from(e)),
        };
    }
}