de_ref/
lib.rs

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    // Identical to the above but with support for unit struct
20    // Can you even Deref as () ???
21    // let inner_access = match data.fields {
22    //     syn::Fields::Named(field) => {let},
23    //     syn::Fields::Unnamed(field) => quote! { #field.0 },
24    //     syn::Fields::Unit => return Err(quote! {"Struct unit field not supported yet"}),
25    // };
26
27    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    // Parse the macro input
86    let input = syn::parse_macro_input!(item as syn::DeriveInput);
87
88    // Access the inner type
89    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    // Parse the macro input
117    let input = syn::parse_macro_input!(item as syn::DeriveInput);
118
119    // Access the inner type
120    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}