1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5
6fn access_struct_inner(
7 data: &syn::DataStruct,
8) -> Result<(proc_macro2::TokenStream, &syn::Type, bool), proc_macro2::TokenStream> {
9 if data.fields.len() != 1 {
10 return Err(quote! {"Struct must have a single field to derive Deref"});
11 }
12 let field = data.fields.iter().next().unwrap();
13 let inner_name = &field
14 .ident
15 .as_ref()
16 .map(|n| quote! { #n })
17 .unwrap_or(quote! { 0 });
18
19 let (ty, add_ref) = match &field.ty {
28 syn::Type::Reference(ty) => (ty.elem.as_ref(), false),
29 _ => (&field.ty, true),
30 };
31
32 Ok((
33 quote! {
34 self.#inner_name
35 },
36 ty,
37 add_ref,
38 ))
39}
40
41fn access_enum_inner(
42 data: &syn::DataEnum,
43) -> Result<(proc_macro2::TokenStream, &syn::Type, bool), proc_macro2::TokenStream> {
44 if data.variants.len() != 1 {
45 return Err(quote! {"Enum must have a single variant to derive Deref"});
46 }
47 let variant = data.variants.iter().next().unwrap();
48 let v_ident = &variant.ident;
49
50 if variant.fields.len() != 1 {
51 return Err(quote! {"Enum variant must have a single field to derive Deref"});
52 }
53
54 let field = variant.fields.iter().next().unwrap();
55 let _inner_name = &field.ident;
56
57 let (ty, add_ref) = match &field.ty {
58 syn::Type::Reference(ty) => (ty.elem.as_ref(), false),
59 _ => (&field.ty, false),
60 };
61
62 Ok((
63 quote! {
64 match self {
65 Self::#v_ident(k) => k
66 }
67 },
68 ty,
69 add_ref,
70 ))
71}
72
73fn access_inner(
74 data: &syn::Data,
75) -> Result<(proc_macro2::TokenStream, &syn::Type, bool), proc_macro2::TokenStream> {
76 match data {
77 syn::Data::Struct(data) => access_struct_inner(data),
78 syn::Data::Enum(data) => access_enum_inner(data),
79 _ => Err(quote! {"Only structs and enums can derive Deref"}),
80 }
81}
82
83#[proc_macro_derive(Deref)]
84pub fn deref(item: TokenStream) -> TokenStream {
85 let input = syn::parse_macro_input!(item as syn::DeriveInput);
87
88 let (access_inner, ty, add_ref) = match access_inner(&input.data) {
90 Ok(inner) => inner,
91 Err(err) => return quote! { compile_error!(#err) }.into(),
92 };
93
94 let name = &input.ident;
95 let gens = &input.generics;
96
97 let (target_ref, inner_ref) = if add_ref {
98 (quote! {}, quote! { & })
99 } else {
100 (quote! {}, quote! {})
101 };
102
103 let derived = quote! {
104 impl #gens std::ops::Deref for #name #gens {
105 type Target = #target_ref #ty;
106 fn deref(&self) -> &Self::Target {
107 #inner_ref #access_inner
108 }
109 }
110 };
111 derived.into()
112}
113
114#[proc_macro_derive(DerefMut)]
115pub fn deref_mut(item: TokenStream) -> TokenStream {
116 let input = syn::parse_macro_input!(item as syn::DeriveInput);
118
119 let (access_inner, _, add_ref) = match access_inner(&input.data) {
121 Ok(inner) => inner,
122 Err(err) => return quote! { compile_error!(#err) }.into(),
123 };
124
125 let inner_ref = if add_ref {
126 quote! { &mut }
127 } else {
128 quote! {}
129 };
130
131 let name = &input.ident;
132 let gens = &input.generics;
133
134 let derived = quote! {
135 impl #gens std::ops::DerefMut for #name #gens {
136 fn deref_mut(&mut self) -> &mut Self::Target {
137 #inner_ref #access_inner
138 }
139 }
140 };
141 derived.into()
142}