spatialos-macro 0.2.4

Procmacro crate used to expand SpatialOS component and types created with spatialos-codegen
Documentation
use proc_macro::TokenStream;
use syn::{Ident, ItemEnum, Variant};

use super::get_value;

#[derive(Debug)]
pub struct VariantAST {
    pub value: u32,
    pub name: Ident,
}

impl From<&Variant> for VariantAST {
    fn from(input: &Variant) -> Self {
        let name = input.ident.clone();
        let value = get_value(&input.attrs).expect("Can't find value for variant");
        Self { name, value }
    }
}

#[derive(Debug)]
pub struct EnumAST<'a> {
    pub name: &'a Ident,
    pub variants: Vec<VariantAST>,
}

impl<'a> From<&'a ItemEnum> for EnumAST<'a> {
    fn from(input: &'a ItemEnum) -> Self {
        let name = &input.ident;
        let variants = input
            .variants
            .iter()
            .map(VariantAST::from)
            .collect::<Vec<_>>();
        Self { name, variants }
    }
}

impl<'a> Into<TokenStream> for EnumAST<'a> {
    fn into(self) -> TokenStream {
        let name = self.name;

        let from_u32 = {
            let variants = self
                .variants
                .iter()
                .map(|variant| {
                    let value = variant.value;
                    let ident = &variant.name;
                    quote! { #value => #name :: #ident}
                })
                .collect::<Vec<_>>();
            quote! {
                impl From<u32> for #name {
                    fn from(data: u32) -> Self {
                        match data {
                            #(#variants,)*
                            _ => panic!("Invalid data")
                        }
                    }
                }
            }
        };

        let into_u32 = {
            let variants = self
                .variants
                .iter()
                .map(|variant| {
                    let value = variant.value;
                    let ident = &variant.name;
                    quote! { #name :: #ident => #value}
                })
                .collect::<Vec<_>>();
            quote! {
                impl Into<u32> for #name {
                    fn into(self) -> u32 {
                        match self {
                            #(#variants,)*
                        }
                    }
                }

                impl Into<u32> for &#name {
                    fn into(self) -> u32 {
                        match *self {
                            #(#variants,)*
                        }
                    }
                }
            }
        };

        let as_ref = {
            quote! {
                impl AsRef<#name> for #name {
                    fn as_ref(&self) -> &#name {
                        self
                    }
                }
            }
        };

        let result = quote! {
            #[automatically_derived]
            #[allow(unused_qualifications)]
            #from_u32

            #[automatically_derived]
            #[allow(unused_qualifications)]
            #into_u32

            #[automatically_derived]
            #[allow(unused_qualifications)]
            #as_ref
        };
        result.into()
    }
}