extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields};
#[proc_macro_attribute]
pub fn from(input: TokenStream, annotated_item: TokenStream) -> TokenStream {
let target_enum_path = parse_macro_input!(input as syn::Path);
let input_enum = parse_macro_input!(annotated_item as DeriveInput);
let input_enum_name = input_enum.clone().ident;
let data = match input_enum.clone().data {
Data::Enum(data) => data,
_ => panic!("convert_enum can only be applied to enums"),
};
let mut to_variants = Vec::new();
for variant in data.variants {
let variant_name = variant.ident;
match variant.fields {
Fields::Unit => {
to_variants.push(quote! {
#target_enum_path::#variant_name => #input_enum_name::#variant_name,
});
}
_ => panic!("same_enum does not support unnamed or named fields"),
}
}
let expanded = quote! {
impl From<#target_enum_path> for #input_enum_name {
fn from(value: #target_enum_path) -> Self {
match value {
#(#to_variants)*
}
}
}
};
let output = quote! {
#input_enum
#expanded
};
TokenStream::from(output)
}
#[proc_macro_attribute]
pub fn to(input: TokenStream, annotated_item: TokenStream) -> TokenStream {
let target_enum_path = parse_macro_input!(input as syn::Path);
let input_enum = parse_macro_input!(annotated_item as DeriveInput);
let input_enum_name = input_enum.clone().ident;
let data = match input_enum.clone().data {
Data::Enum(data) => data,
_ => panic!("convert_enum can only be applied to enums"),
};
let mut from_variants = Vec::new();
for variant in data.variants {
let variant_name = variant.ident;
match variant.fields {
Fields::Unit => {
from_variants.push(quote! {
#input_enum_name::#variant_name => #target_enum_path::#variant_name,
});
}
_ => panic!("same_enum does not support unnamed or named fields"),
}
}
let expanded = quote! {
impl From<#input_enum_name> for #target_enum_path {
fn from(value: #input_enum_name) -> Self {
match value {
#(#from_variants)*
}
}
}
};
let output = quote! {
#input_enum
#expanded
};
TokenStream::from(output)
}