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