leptos_i18n_codegen 0.6.2

codegen crate for the leptos_i18n crate
Documentation
use proc_macro2::TokenStream;
use quote::{ToTokens, TokenStreamExt, format_ident, quote};
use syn::Token;

pub enum Keys {
    SingleKey(syn::Ident),
    Subkeys(Vec<syn::Ident>),
}

fn parse_subkeys(input: syn::parse::ParseStream, keys: &mut Vec<syn::Ident>) -> syn::Result<()> {
    keys.push(input.parse()?);
    while input.peek(Token![.]) {
        input.parse::<Token![.]>()?;
        keys.push(input.parse()?);
    }
    Ok(())
}

impl syn::parse::Parse for Keys {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        let first_key = input.parse()?;
        let dot = input.peek(Token![.]);
        if dot || input.peek(Token![::]) {
            if dot {
                input.parse::<Token![.]>()?;
            } else {
                input.parse::<Token![::]>()?;
            }
            let mut keys = vec![first_key];
            parse_subkeys(input, &mut keys)?;
            Ok(Keys::Subkeys(keys))
        } else {
            Ok(Keys::SingleKey(first_key))
        }
    }
}

impl quote::ToTokens for Keys {
    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
        match self {
            Keys::SingleKey(key) => tokens.append(key.clone()),
            Keys::Subkeys(keys) => tokens.append_separated(keys, quote!(().)),
        }
    }
}

#[derive(Debug, Clone)]
pub enum EitherOfWrapper {
    Single,
    Duo,
    Multiple(syn::Ident),
    Nested(Box<Self>),
}

impl EitherOfWrapper {
    pub fn new(size: usize) -> EitherOfWrapper {
        match size {
            0 => {
                unreachable!("0 locales ? how is this possible ? should have been checked by now.")
            }
            1 => EitherOfWrapper::Single,
            2 => EitherOfWrapper::Duo,
            3..=16 => EitherOfWrapper::Multiple(format_ident!("EitherOf{}", size)),
            17.. => EitherOfWrapper::Nested(Box::new(Self::new(size - 15))),
        }
    }

    pub fn wrap<T: ToTokens>(&self, i: usize, ts: T) -> TokenStream {
        const LETTERS: [char; 16] = [
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
        ];
        match self {
            EitherOfWrapper::Single => ts.into_token_stream(),
            EitherOfWrapper::Duo if i == 0 => {
                quote!(l_i18n_crate::reexports::leptos::either::Either::Left(#ts))
            }
            EitherOfWrapper::Duo => {
                quote!(l_i18n_crate::reexports::leptos::either::Either::Right(#ts))
            }
            EitherOfWrapper::Multiple(ident) => {
                let variant = format_ident!("{}", LETTERS[i]);
                quote!(l_i18n_crate::reexports::leptos::either::#ident::#variant(#ts))
            }
            EitherOfWrapper::Nested(last) => match i {
                0..=14 => {
                    let variant = format_ident!("{}", LETTERS[i]);
                    quote!(l_i18n_crate::reexports::leptos::either::EitherOf16::#variant(#ts))
                }
                15.. => {
                    let variant = format_ident!("{}", LETTERS[15]);
                    let ts = last.wrap(i - 15, ts);
                    quote!(l_i18n_crate::reexports::leptos::either::EitherOf16::#variant(#ts))
                }
            },
        }
    }
}

pub fn fit_in_leptos_tuple(values: &[TokenStream]) -> TokenStream {
    const TUPLE_MAX_SIZE: usize = 26;
    let values_len = values.len();
    if values_len <= TUPLE_MAX_SIZE {
        quote!((#(#values,)*))
    } else {
        let chunk_size = values_len.div_ceil(TUPLE_MAX_SIZE);
        let values = values.chunks(chunk_size).map(fit_in_leptos_tuple);
        quote!((#(#values,)*))
    }
}