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::{
    json::custom::{ErrHandling, MethodCall},
    metas_holder::MetasHolder,
    types::custom::Processing,
    NullHandling,
};

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

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

    #[inline]
    pub fn try_build_custom_null<H: MetasHolder>(
        ty: TokenStream2,
        vec_var: &Ident,
        idx_var: TokenStream2,
        metas_holder: Option<H>,
    ) -> Result<Self, TokenStream> {
        let processing;

        match metas_holder {
            Some(metas_holder) => {
                processing = Processing::try_build::<H>(&metas_holder, &ty)?;
            }

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

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

        Ok(Self::build_custom(
            null_handling,
            MethodCall::new(&ty),
            idx_var,
            processing,
            quote! {
                #vec_var.push(::from::Null::<#ty>::Some(val));
            },
            ErrHandling::new(),
        ))
    }

    #[inline]
    pub fn try_build_custom_not_null<H: MetasHolder>(
        ty: TokenStream2,
        vec_var: &Ident,
        idx_var: TokenStream2,
        metas_holder: Option<H>,
        dflt_lang: &str,
    ) -> Result<Self, TokenStream> {
        let processing;
        let null_handling;

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

                null_handling = NullHandling::try_build(
                    &metas_holder,
                    &idx_var,
                    &dflt_lang,
                    || -> TokenStream2 {
                        quote! {String::from("expected: object, found: null")}
                    },
                )?;
            }

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

                null_handling = NullHandling::new_dflt(
                    &idx_var,
                    quote! {String::from("expected: object, found: null")},
                );
            }
        };

        Ok(Self::build_custom(
            null_handling,
            MethodCall::new(&ty),
            idx_var,
            processing,
            quote! {
                #vec_var.push(val);
            },
            ErrHandling::new(),
        ))
    }

    #[inline]
    fn build_custom(
        null_handling: NullHandling,
        method_call: MethodCall,
        idx_var: TokenStream2,
        processing: Processing,
        elem_push: TokenStream2,
        err_handling: ErrHandling,
    ) -> Self {
        Self {
            none: custom_field_parsing_match_temp(
                null_handling.none,
                method_call.none,
                &idx_var,
                processing.valdg,
                &elem_push,
                err_handling.none,
            ),

            lang: custom_field_parsing_match_temp(
                null_handling.lang,
                method_call.lang,
                &idx_var,
                processing.valdg_lang,
                &elem_push,
                err_handling.lang,
            ),

            stack_errs: custom_field_parsing_match_temp(
                null_handling.stack_errs,
                method_call.stack_errs,
                &idx_var,
                processing.valdg_stack_errs,
                &elem_push,
                err_handling.stack_errs,
            ),

            stack_errs_lang: custom_field_parsing_match_temp(
                null_handling.stack_errs_lang,
                method_call.stack_errs_lang,
                &idx_var,
                processing.valdg_stack_errs_lang,
                &elem_push,
                err_handling.stack_errs_lang,
            ),
        }
    }
}

#[inline]
fn custom_field_parsing_match_temp(
    null_handling: TokenStream2,
    method_call: TokenStream2,
    idx_var: &TokenStream2,
    valdg: TokenStream2,
    elem_push: &TokenStream2,
    err_handling: TokenStream2,
) -> TokenStream2 {
    quote! {
        byte = ::from::json::utils::get_or_unexpected_end(json, idx)?;
        if byte == b'n' {
            if let Err(e) = ::from::json::utils::skip_null(json, idx, "{") {
                return Err(From::from(e));
            };

            #null_handling
        } else {
            let mut path = path.clone();
            path.push(From::from(#idx_var));

            match #method_call {
                Ok(val) => {
                    #valdg
                    #elem_push
                    *idx += 1;
                },

                Err(e) => {
                    #err_handling
                }
            };
        };
    }
}