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
85
86
87
88
89
90
91
92
93

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, punctuated::Punctuated};

trait Forwarder {}

#[proc_macro_derive(Forwarder, attributes(forward))]
pub fn forwarder(input_stream: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input_stream as syn::ItemEnum);
    let ident = input.ident.clone();
    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl().to_owned();

    let mut to_derive_idents = Vec::new();
    let mut to_derive_variants = Vec::new();
    let mut to_derive_args: Vec<Vec<syn::Path>> = Vec::new();

    for variant in input.variants.into_iter() {
        for attr in variant.attrs {
            if attr.path().is_ident("forward") {
                match attr.parse_args_with(
                    Punctuated::<syn::Path, syn::Token!(,)>::parse_terminated
                ) {
                    Ok(args) => {
                        to_derive_args.push(args.into_iter().collect());
                    },
                    Err(_) => {
                        to_derive_args.push(Vec::new());
                    }
                };

                to_derive_idents.push(match variant.fields {
                    syn::Fields::Unnamed(ref fields) => {
                        fields.unnamed.clone().into_iter().next().expect("expected a single field")
                    },
                    _ => panic!("expected unnamed tuple-like fields")
                });
                to_derive_variants.push(variant.ident.clone());
            }
        }
    }

    let gen = quote! {
        #(
            impl #impl_generics From<#to_derive_idents> for #ident #type_generics #where_clause {
                fn from(value: #to_derive_idents) -> #ident #type_generics {
                    Self::#to_derive_variants(value)
                }
            }

            #(
                impl #impl_generics From<#to_derive_args> for #ident #type_generics #where_clause {
                    fn from(value: #to_derive_args) -> #ident #type_generics {
                        Self::#to_derive_variants(value.into())
                    }
                }
            )*
        )*
    };

    gen.into()
}

#[proc_macro_attribute]
pub fn deref(args: TokenStream, input_stream: TokenStream) -> TokenStream {
    let input: syn::ItemStruct = parse_macro_input!(input_stream);
    let field_name: syn::Ident = parse_macro_input!(args);

    let ident = input.ident.clone();
    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();

    let mut fields_iter = input.fields.iter();
    let field_type = loop {
        if let Some(field) = fields_iter.next() {
            if field.ident.clone().expect("expected struct to be {}") == field_name {
                break field.ty.clone();
            }
        } else {
            panic!("field not found");
        }
    };

    let gen = quote! {
        #input
        impl #impl_generics std::ops::Deref for #ident #type_generics #where_clause {
            type Target = #field_type;
            fn deref(&self) -> &Self::Target {
                &self.#field_name
            }
        }
    };
    gen.into()
}