enum_handler_core 0.1.0

This crate is part of the enum_handler library. Do not use it directly.
Documentation
use crate::{enum_handler_args::EnumHandlerArgs, Error, Result};
use heck::ToSnakeCase;
use quote::format_ident;
use syn::{Data, DeriveInput, Fields, Ident, Type, Variant, Visibility};

pub struct Enum {
    pub vis: Visibility,
    pub name: Ident,
    pub variants: Vec<EnumVariant>,
}

impl Enum {
    pub fn new(
        derive_input: &DeriveInput,
        args: &EnumHandlerArgs,
    ) -> Result<Self> {
        let data_enum = match &derive_input.data {
            Data::Enum(data_enum) => data_enum,
            _ => return Err(Error::NotEnum),
        };

        let vis = derive_input
            .vis
            .clone();
        let name = derive_input
            .ident
            .clone();
        let variants: Result<Vec<EnumVariant>> = data_enum
            .variants
            .iter()
            .map(|v| EnumVariant::new(v, name.clone(), args))
            .collect();

        match variants {
            Ok(variants) => Ok(Enum {
                vis,
                name,
                variants,
            }),
            Err(e) => Err(e),
        }
    }
}

pub enum EnumVariantType {
    Unit,
    Tuple,
    Struct,
}

pub struct EnumVariant {
    pub enum_name: Ident,
    pub name: Ident,
    pub variant_type: EnumVariantType,
    pub return_type: Type,
    pub fields: Vec<(Option<Ident>, Type)>,
}

impl EnumVariant {
    pub fn new(
        variant: &Variant,
        enum_name: Ident,
        args: &EnumHandlerArgs,
    ) -> Result<Self> {
        let name = variant
            .ident
            .clone();
        let fields = variant
            .fields
            .iter()
            .map(|field| {
                let name = field
                    .ident
                    .clone();
                let ty = field
                    .ty
                    .clone();
                (name, ty)
            })
            .collect();
        let return_type = args.get_return_type()?;
        let variant_type = match variant.fields {
            Fields::Unit => EnumVariantType::Unit,
            Fields::Named(_) => EnumVariantType::Struct,
            Fields::Unnamed(_) => EnumVariantType::Tuple,
        };
        Ok(EnumVariant {
            enum_name,
            name,
            variant_type,
            return_type,
            fields,
        })
    }

    pub fn get_variant_handler_name(
        &self,
        args: &EnumHandlerArgs,
    ) -> Ident {
        format_ident!(
            "{}_{}",
            args.get_handler_name(),
            self.name
                .to_string()
                .to_snake_case()
        )
    }

    pub fn parameter_name(
        &self,
        field_name: &Option<Ident>,
        index: usize,
    ) -> Ident {
        if let Some(name) = field_name {
            return name.clone();
        }

        if self.is_single_field() {
            format_ident!("arg")
        } else {
            format_ident!("arg{}", index)
        }
    }

    fn is_single_field(&self) -> bool {
        self.fields
            .len()
            == 1
    }
}