int-enum-impl 0.5.0

Implementation detail of the `int-enum` crate.
Documentation
use proc_macro2::TokenStream;
use quote::{quote, TokenStreamExt};
use syn::{DeriveInput, Path, Result};

use crate::ast::Input;
use crate::{serde, util};

pub fn derive(node: &DeriveInput) -> Result<TokenStream> {
    let input = Input::from_syn(node)?;

    util::with_crate_path(|int_enum| {
        let mut output = base(int_enum, &input);

        if cfg!(feature = "convert") {
            output.append_all(convert(int_enum, &input));
        }
        if cfg!(feature = "serde") {
            output.append_all(serde::serde_impl(int_enum, &input)?);
        }

        Ok(output)
    })
}

pub fn base(int_enum: &Path, input: &Input) -> TokenStream {
    let enum_ty = &input.ident;
    let int_ty = &input.repr;

    let to_int_arms = input.variants.iter().map(|(variant, value)| {
        quote! {
            #enum_ty::#variant => { #value }
        }
    });

    let from_int_arms = input.variants.iter().map(|(variant, value)| {
        quote! {
            #value => { #int_enum::__private::Result::Ok(#enum_ty::#variant) }
        }
    });

    quote! {
        #[automatically_derived]
        impl #int_enum::IntEnum for #enum_ty {
            type Int = #int_ty;

            #[inline]
            fn int_value(self) -> Self::Int {
                match self {
                    #(#to_int_arms)*
                }
            }

            #[inline]
            fn from_int(n: Self::Int) -> #int_enum::__private::Result<Self, #int_enum::IntEnumError<Self>>
            where
                Self: Sized,
            {
                match n {
                    #(#from_int_arms)*
                    _ => { #int_enum::__private::Result::Err(#int_enum::IntEnumError::__new(n)) }
                }
            }
        }
    }
}

fn convert(int_enum: &Path, input: &Input) -> TokenStream {
    let enum_ty = &input.ident;
    let int_ty = &input.repr;

    let from_enum = quote! {
        #[automatically_derived]
        impl #int_enum::__private::From<#enum_ty> for #int_ty {
            #[inline]
            fn from(n: #enum_ty) -> Self {
                #int_enum::IntEnum::int_value(n)
            }
        }
    };

    let try_from_int = quote! {
        #[automatically_derived]
        impl #int_enum::__private::TryFrom<#int_ty> for #enum_ty {
            type Error = #int_enum::IntEnumError<Self>;

            #[inline]
            fn try_from(n: #int_ty) -> #int_enum::__private::Result<Self, Self::Error> {
                #int_enum::IntEnum::from_int(n)
            }
        }
    };

    quote! {
        #from_enum
        #try_from_int
    }
}