1extern crate proc_macro;
2
3use swc_macros_common::prelude::*;
4use syn::*;
5
6#[proc_macro_derive(FromVariant)]
9pub fn derive_from_variant(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
10 let input = parse::<DeriveInput>(input).expect("failed to parse input as DeriveInput");
11
12 let item = derive(input)
13 .into_iter()
14 .fold(TokenStream::new(), |mut t, item| {
15 item.to_tokens(&mut t);
16 t
17 });
18
19 print("derive(FromVariant)", item)
20}
21
22fn derive(
23 DeriveInput {
24 generics,
25 data,
26 ident,
27 ..
28 }: DeriveInput,
29) -> Vec<ItemImpl> {
30 let variants = match data {
31 Data::Enum(DataEnum { variants, .. }) => variants,
32 _ => panic!("#[derive(FromVariant)] only works for an enum."),
33 };
34
35 let mut from_impls: Vec<ItemImpl> = Vec::new();
36
37 for v in variants {
38 let variant_name = v.ident;
39 match v.fields {
40 Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
41 if unnamed.len() != 1 {
42 panic!(
43 "#[derive(FromVariant)] requires all variants to be tuple with exactly \
44 one field"
45 )
46 }
47 let field = unnamed.into_iter().next().unwrap();
48
49 let variant_type = &field.ty;
50
51 let from_impl: ItemImpl = parse_quote!(
52 impl From<#variant_type> for #ident {
53 fn from(v: #variant_type) -> Self {
54 #ident::#variant_name(v)
55 }
56 }
57 );
58
59 let from_impl = from_impl.with_generics(generics.clone());
60
61 from_impls.push(from_impl);
62 }
63 _ => panic!(
64 "#[derive(FromVariant)] requires all variants to be tuple with exactly one field"
65 ),
66 }
67 }
68
69 from_impls
70}