enum-methods 0.0.8

Generates methods for each enum variant.
Documentation
use util::*;
use syn::*;
use quote;

pub(crate) fn impl_enum_as_getters(ast: &DeriveInput) -> quote::Tokens {
    let ref name = ast.ident;

    let variants =
        if let Body::Enum(ref e) = ast.body { e }
        else { unreachable!() };

    macro_rules! getter_filter {
        () => {
            variants.iter()
                .filter(|v| if let VariantData::Tuple(_) = v.data { true } else { false })
        };
    }

    let variant_names = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| v.ident.clone())
        .collect::<Vec<Ident>>();

    let function_names = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| format!("as_{}", to_snake_case(&v.ident)).into())
        .collect::<Vec<Ident>>();

    let function_name_strs = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| v.ident.to_string().to_lowercase())
        .collect::<Vec<String>>();

    let variant_types = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| &v.data.fields()[0].ty)
        .map(|ty| Ty::Rptr(None, Box::new(MutTy { ty: ty.clone(), mutability: Mutability::Immutable })))
        .collect::<Vec<Ty>>();

    let getter_names = vec!(name.clone(); variant_types.len());

    let mut tokens = quote! {
        #[allow(dead_code)]
        impl #name {
            #(pub fn #function_names(&self) -> #variant_types {
                    if let &#getter_names::#variant_names(ref v) = self {
                        v
                    }
                    else {
                        panic!(concat!("called as_", #function_name_strs, "() on {:?}"), self);
                    }
                }
            )*
        }
    };

    let variant_names = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| v.ident.clone())
        .collect::<Vec<Ident>>();

    let function_names = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| format!("as_{}", to_snake_case(&v.ident)).into())
        .collect::<Vec<Ident>>();

    let function_name_strs = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| v.ident.to_string().to_lowercase())
        .collect::<Vec<String>>();

    let variant_types = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| Ty::Tup(v.data.fields().iter().map(|field| Ty::Rptr(None, Box::new(MutTy { ty: field.ty.clone(), mutability: Mutability::Immutable }))).collect::<Vec<Ty>>()))
        .collect::<Vec<Ty>>();

    let getter_names_multiple = vec!(name.clone(); variant_types.len());

    let tuple_args = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| UniqueIdentifierIterator::new().take(v.data.fields().len()))
        .collect::<Vec<_>>();

    let tuple_args2 = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| UniqueIdentifierIterator::new().take(v.data.fields().len()))
        .collect::<Vec<_>>();

    tokens.append(quote! {
        #[allow(dead_code)]
        impl #name {
            #(pub fn #function_names(&self) -> #variant_types {
                    if let &#getter_names_multiple::#variant_names(#(ref #tuple_args),*) = self {
                        (#(#tuple_args2), *)
                    }
                    else {
                        panic!(concat!("called as_", #function_name_strs, "() on {:?}"), self);
                    }
                }
            )*
        }
    });

    tokens
}

pub(crate) fn impl_enum_into_getters(ast: &DeriveInput) -> quote::Tokens {
    let ref name = ast.ident;

    let variants =
        if let Body::Enum(ref e) = ast.body { e }
        else { unreachable!() };

    macro_rules! getter_filter {
        () => {
            variants.iter()
                .filter(|v| if let VariantData::Tuple(_) = v.data { true } else { false })
        };
    }

    let variant_names = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| v.ident.clone())
        .collect::<Vec<Ident>>();

    let function_names = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| format!("into_{}", to_snake_case(&v.ident)).into())
        .collect::<Vec<Ident>>();

    let function_name_strs = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| v.ident.to_string().to_lowercase())
        .collect::<Vec<String>>();

    let variant_types = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| v.data.fields()[0].ty.clone())
        .collect::<Vec<Ty>>();

    let getter_names = vec!(name.clone(); variant_types.len());

    let mut tokens = quote! {
        #[allow(dead_code)]
        impl #name {
            #(pub fn #function_names(self) -> #variant_types {
                    if let #getter_names::#variant_names(v) = self {
                        v
                    }
                    else {
                        panic!(concat!("called into_", #function_name_strs, "() on {:?}"), self);
                    }
                }
            )*
        }
    };

    let variant_names = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| v.ident.clone())
        .collect::<Vec<Ident>>();

    let function_names = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| format!("into_{}", to_snake_case(&v.ident)).into())
        .collect::<Vec<Ident>>();

    let function_name_strs = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| v.ident.to_string().to_lowercase())
        .collect::<Vec<String>>();

    let variant_types = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| Ty::Tup(v.data.fields().iter().map(|field| field.ty.clone()).collect::<Vec<Ty>>()))
        .collect::<Vec<Ty>>();

    let getter_names = vec!(name.clone(); variant_types.len());

    let tuple_args = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| UniqueIdentifierIterator::new().take(v.data.fields().len()))
        .collect::<Vec<_>>();

    let tuple_args2 = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| UniqueIdentifierIterator::new().take(v.data.fields().len()))
        .collect::<Vec<_>>();

    tokens.append(quote! {
        #[allow(dead_code)]
        impl #name {
            #(pub fn #function_names(self) -> #variant_types {
                    if let #getter_names::#variant_names(#(#tuple_args),*) = self {
                        (#(#tuple_args2), *)
                    }
                    else {
                        panic!(concat!("called into_", #function_name_strs, "() on {:?}"), self);
                    }
                }
            )*
        }
    });

    tokens
}

pub(crate) fn impl_enum_to_getters(ast: &DeriveInput) -> quote::Tokens {
    let ref name = ast.ident;

    let variants =
        if let Body::Enum(ref e) = ast.body { e }
        else { unreachable!() };

    macro_rules! getter_filter {
        () => {
            variants.iter()
                .filter(|v| if let VariantData::Tuple(_) = v.data { true } else { false })
        };
    }

    let variant_names = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| v.ident.clone())
        .collect::<Vec<Ident>>();

    let function_names = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| format!("to_{}", to_snake_case(&v.ident)).into())
        .collect::<Vec<Ident>>();

    let function_name_strs = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| v.ident.to_string().to_lowercase())
        .collect::<Vec<String>>();

    let variant_types = getter_filter!()
        .filter(|v| v.data.fields().len() == 1)
        .map(|v| v.data.fields()[0].ty.clone())
        .collect::<Vec<Ty>>();

    let getter_names = vec!(name.clone(); variant_types.len());

    let mut tokens = quote! {
        #[allow(dead_code)]
        impl #name {
            #(pub fn #function_names(&self) -> #variant_types {
                    if let &#getter_names::#variant_names(ref v) = self {
                        v.clone()
                    }
                    else {
                        panic!(concat!("called to_", #function_name_strs, "() on {:?}"), self);
                    }
                }
            )*
        }
    };

    let variant_names = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| v.ident.clone())
        .collect::<Vec<Ident>>();

    let function_names = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| format!("to_{}", to_snake_case(&v.ident)).into())
        .collect::<Vec<Ident>>();

    let function_name_strs = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| v.ident.to_string().to_lowercase())
        .collect::<Vec<String>>();

    let variant_types = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| Ty::Tup(v.data.fields().iter().map(|field| field.ty.clone()).collect::<Vec<Ty>>()))
        .collect::<Vec<Ty>>();

    let getter_names = vec!(name.clone(); variant_types.len());

    let tuple_args = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| UniqueIdentifierIterator::new().take(v.data.fields().len()))
        .collect::<Vec<_>>();

    let tuple_args2 = getter_filter!()
        .filter(|v| v.data.fields().len() > 1)
        .map(|v| UniqueIdentifierIterator::new().take(v.data.fields().len()))
        .collect::<Vec<_>>();

    tokens.append(quote! {
        #[allow(dead_code)]
        impl #name {
            #(pub fn #function_names(&self) -> #variant_types {
                    if let &#getter_names::#variant_names(#(ref #tuple_args),*) = self {
                        (#(#tuple_args2.clone()), *)
                    }
                    else {
                        panic!(concat!("called to_", #function_name_strs, "() on {:?}"), self);
                    }
                }
            )*
        }
    });

    tokens
}