tyenum 0.1.0

Attribute macro for type enums.
Documentation
/*!
Attribute macro for less verbose creation of enums having different types as variants. Also automatically implements From.

## Usage:
```rs
struct A;
struct B;
struct C;
struct D;

#[tyenum]
enum Test {
    A,
    BB(B),
    C(C),
}
```

results in:

```rs
enum Test {
    A(A),
    BB(B),
    C(C),
}

impl From<A> for Test {
    fn from(variant: A) -> Self {
        Test::A(variant)
    }
}

impl From<B> for Test {
    fn from(variant: B) -> Self {
        Test::BB(variant)
    }
}

impl From<C> for Test {
    fn from(variant: C) -> Self {
        Test::C(variant)
    }
}
```
!*/
extern crate proc_macro;

use proc_macro2::TokenStream;
use quote::quote;
use syn::{parse2, parse_quote, spanned::Spanned, Error, ItemEnum};

#[doc(hidden)]
#[proc_macro_attribute]
pub fn tyenum(_attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let item: TokenStream = item.into();
    let mut tyenum: ItemEnum = parse2(item).unwrap();
    let name = &tyenum.ident;
    let mut impls = Vec::new();
    for v in tyenum.variants.iter_mut() {
        let mut iter = v.fields.iter();
        if let Some(f) = iter.next() {
            let ident = &v.ident;
            let ty = &f.ty;
            impls.push(quote! {
                impl From<#ty> for #name {
                    fn from(variant: #ty) -> Self {
                        #name::#ident(variant)
                    }
                }
            });
            if let Some(f) = iter.next() {
                return Error::new(f.span(), "maximum one field in variants allowed").to_compile_error().into();
            }
        } else {
            drop(iter);
            let ident = &v.ident;
            impls.push(quote! {
                impl From<#ident> for #name {
                    fn from(variant: #ident) -> Self {
                        #name::#ident(variant)
                    }
                }
            });
            *v = parse_quote!(#ident(#ident));
        }
    }
    quote! (
        #tyenum
        #(#impls)*
    )
    .into()
}