from_variant/
lib.rs

1extern crate proc_macro;
2
3use swc_macros_common::prelude::*;
4use syn::*;
5
6/// Derives [`From`] for all variants. This only supports an enum where every
7/// variant has a single field.
8#[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}