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
80
81
82
83
84
use syn;
use quote::ToTokens;

use proc_macro2::TokenStream as TokenStream2;
use field::{Field, FieldParent, Fields};

#[derive(Debug)]
pub struct Derived<'p, T: 'p> {
    pub derive_input: &'p syn::DeriveInput,
    pub value: &'p T,
}

pub type Variant<'v> = Derived<'v, syn::Variant>;

pub type Struct<'v> = Derived<'v, syn::DataStruct>;

pub type Enum<'v> = Derived<'v, syn::DataEnum>;

impl<'p, T> Derived<'p, T> {
    pub fn from(derive_input: &'p syn::DeriveInput, value: &'p T) -> Self {
        Derived { derive_input, value }
    }
}

impl<'p, T> ::std::ops::Deref for Derived<'p, T> {
    type Target = T;

    fn deref(&self) -> &T {
        self.value
    }
}

impl<'p, T: ToTokens> ToTokens for Derived<'p, T> {
    fn to_tokens(&self, tokens: &mut TokenStream2) {
        self.value.to_tokens(tokens)
    }
}

impl<'p, T> Copy for Derived<'p, T> { }

impl<'p, T> Clone for Derived<'p, T> {
    fn clone(&self) -> Derived<'p, T> {
        *self
    }
}

impl<'f> Variant<'f> {
    pub fn builder<F: Fn(Field) -> TokenStream2>(&self, f: F) -> TokenStream2 {
        let variant = &self.ident;
        let expression = self.fields().iter().map(f);
        let enum_name = &self.derive_input.ident;
        if self.fields().are_named() {
            let field_name = self.fields.iter().map(|f| f.ident.as_ref().unwrap());
            quote! {
                #enum_name::#variant { #(#field_name: #expression),* }
            }
        } else if self.fields().are_unnamed() {
            quote! {
                #enum_name::#variant(#(#expression),*)
            }
        } else {
            quote! {
                #enum_name::#variant
            }
        }
    }

    pub fn fields(self) -> Fields<'f> {
        FieldParent::Variant(self).fields()
    }
}

impl<'p> Enum<'p> {
    pub fn variants(self) -> impl Iterator<Item = Variant<'p>> {
        self.value.variants.iter()
            .map(move |v| Derived::from(&self.derive_input, v))
    }
}

impl<'p> Struct<'p> {
    pub fn fields(self) -> Fields<'p> {
        FieldParent::Struct(self).fields()
    }
}