serde-enum-str 0.3.2

Serialize and deserialize enum string
Documentation
use alloc::vec::Vec;

use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens, TokenStreamExt as _};
use syn::Ident;

use super::input::Input;

//
pub struct SerdeEnum<'a> {
    input: &'a Input,
    category: SerdeEnumCategory,
}
pub enum SerdeEnumCategory {
    Ser,
    De,
}
impl<'a> SerdeEnum<'a> {
    pub fn new(input: &'a Input, category: SerdeEnumCategory) -> Self {
        Self { input, category }
    }
    pub fn ident(&self) -> Ident {
        format_ident!("__{}{}", self.input.ident, self.suffix())
    }
    fn suffix(&self) -> &'static str {
        match self.category {
            SerdeEnumCategory::Ser => "Ser",
            SerdeEnumCategory::De => "De",
        }
    }
}
impl<'a> ToTokens for SerdeEnum<'a> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let input = self.input;

        let derive_serde = match self.category {
            SerdeEnumCategory::Ser => quote! {
                #[derive(serde::Serialize)]
            },
            SerdeEnumCategory::De => quote! {
                #[derive(serde::Deserialize)]
            },
        };
        let serde_rename_all = if let Some(rename_all) = &input.rename_all {
            match self.category {
                SerdeEnumCategory::Ser => {
                    if let Some(serialize) = &rename_all.ser_rule() {
                        let s = serialize.to_rename_all_str();
                        quote!(#[serde(rename_all(serialize = #s))])
                    } else {
                        quote!()
                    }
                }
                SerdeEnumCategory::De => {
                    if let Some(deserialize) = &rename_all.de_rule() {
                        let s = deserialize.to_rename_all_str();
                        quote!(#[serde(rename_all(deserialize = #s))])
                    } else {
                        quote!()
                    }
                }
            }
        } else {
            quote!()
        };
        let ident = self.ident();
        let variants = &input
            .variants
            .iter()
            .map(|variant| {
                let ident = &variant.ident;
                let serde_rename = if let Some(rename) = &variant.rename {
                    match self.category {
                        SerdeEnumCategory::Ser => {
                            if let Some(serialize) = &rename.ser_name() {
                                quote!(#[serde(rename(serialize = #serialize))])
                            } else {
                                quote!()
                            }
                        }
                        SerdeEnumCategory::De => {
                            if let Some(deserialize) = &rename.de_name() {
                                quote!(#[serde(rename(deserialize = #deserialize))])
                            } else {
                                quote!()
                            }
                        }
                    }
                } else {
                    quote!()
                };
                let serde_alias = match self.category {
                    SerdeEnumCategory::Ser => quote!(),
                    SerdeEnumCategory::De => {
                        if let Some(alias_vec) = &variant.alias_vec {
                            let tokens = alias_vec
                                .iter()
                                .map(|alias| {
                                    let alias = &alias.0;
                                    quote!(#[serde(alias = #alias)])
                                })
                                .collect::<Vec<_>>();
                            quote! {
                                #(#tokens)*
                            }
                        } else {
                            quote!()
                        }
                    }
                };
                let serde_skip = match self.category {
                    SerdeEnumCategory::Ser => {
                        if variant.skip_serializing == Some(true) {
                            quote!(#[serde(skip_serializing)])
                        } else {
                            quote!()
                        }
                    }
                    SerdeEnumCategory::De => {
                        if variant.skip_deserializing == Some(true) {
                            quote!(#[serde(skip_deserializing)])
                        } else {
                            quote!()
                        }
                    }
                };
                quote! {
                    #serde_rename
                    #serde_alias
                    #serde_skip
                    #[allow(non_camel_case_types, clippy::all)]
                    #ident,
                }
            })
            .collect::<Vec<_>>();

        let token = quote! {
            #derive_serde
            #serde_rename_all
            #[allow(dead_code, clippy::all)]
            enum #ident {
                #(#variants)*
            }
        };
        tokens.append_all(token);
    }
}