small_derive_deref/
lib.rs

1#![crate_name = "small_derive_deref"]
2//! ## Example
3//! 
4//! ```rust
5//! use std::ops::DerefMut;
6//! use small_derive_deref::{Deref, DerefMut};
7//! 
8//! #[derive(Deref, DerefMut)]
9//! struct WrapperStructDifferentTargetsMultipleGenerics<'a, T> {
10//!     #[DerefTarget]
11//!     field: &'a str,
12//!     #[DerefMutTarget]
13//!     field_mut: &'a str,
14//!     foo: T
15//! }
16//! 
17//! let mut w = WrapperStructDifferentTargetsMultipleGenerics { field: "not rust", field_mut: "rust", foo: "foo"};
18//! assert_eq!(*w, "not rust");
19//! *w = "rUst";
20//! assert_eq!(*w.deref_mut(), "rUst");
21//! 
22//! #[derive(Deref, DerefMut)]
23//! struct WrapperTuple(i32, i32);
24//! 
25//! let mut w = WrapperTuple(1, 3);
26//! *w *= 2;
27//! assert_eq!(*w, 2);
28//! assert_eq!(*w.deref_mut(), 2);
29//! ```
30
31use proc_macro::TokenStream;
32use quote::quote;
33use syn::{parse_macro_input, Data, DeriveInput, Fields};
34
35/// Defines Deref either on a struct or a tuple.<br>
36/// No attribute needed for structs with one field or tuples.<br>
37/// ## Example
38/// 
39/// ```rust
40/// use small_derive_deref::Deref;
41/// 
42/// #[derive(Deref)]
43/// struct WrapperStruct {
44///     field: i32,
45/// }
46/// 
47/// let w = WrapperStruct { field: 1 };
48/// assert_eq!(*w, 1);
49/// 
50/// #[derive(Deref)]
51/// struct WrapperMultipleStruct {
52///     #[DerefTarget]
53///     field1: i32,
54///     field2: i32,
55/// }
56/// 
57/// let w = WrapperMultipleStruct { field1: 1, field2: 2 };
58/// 
59/// assert_eq!(*w, 1);
60/// 
61/// #[derive(Deref)]
62/// struct WrapperTuple(i32);
63/// 
64/// let w = WrapperTuple(1);
65/// assert_eq!(*w, 1);
66/// ```
67#[proc_macro_derive(Deref, attributes(DerefTarget))]
68pub fn derive_deref(input: TokenStream) -> TokenStream {
69    let input = parse_macro_input!(input as DeriveInput);
70    let name = input.ident;
71    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
72
73    let expanded = match input.data {
74        Data::Struct(data_struct) => {
75            match &data_struct.fields {
76                Fields::Named(named) => {
77                    let field = match named.named.len() {
78                        1 => { named.named.first() }
79                        _ => named.named.iter()
80                            .find_map(|field| {
81                                for attr in &field.attrs {
82                                    if attr.path().is_ident("DerefTarget") {
83                                        return Some(field);
84                                    }
85                                }
86                                None
87                            })
88                    };
89
90                    if let Some(field) = field {
91                        let field_name = &field.ident;
92                        let field_type = &field.ty;
93
94                        quote! {
95                            impl #impl_generics std::ops::Deref for #name #type_generics #where_clause {
96                                type Target = #field_type;
97
98                                fn deref(&self) -> &Self::Target {
99                                    &self.#field_name
100                                }
101                            }
102                        }
103                    } else {
104                        panic!("No field with #[DerefTarget]")
105                    }
106                },
107                Fields::Unnamed(unnamed) => {
108                    let field_type = &unnamed.unnamed[0].ty;
109
110                    quote! {
111                        impl #impl_generics std::ops::Deref for #name #type_generics #where_clause {
112                            type Target = #field_type;
113
114                            fn deref(&self) -> &Self::Target {
115                                &self.0
116                            }
117                        }
118                    }
119                    
120                },
121                Fields::Unit => panic!("Deref not implemented for unit structs")
122            }
123        },
124        _ => panic!("Deref only implemented for structs")
125    };
126
127    expanded.into()
128}
129
130
131/// Defines DerefMut either on a struct or a tuple.<br>
132/// No attribute needed for structs with one field or tuples.<br>
133/// # Examples
134/// ## Struct
135/// ```rust
136/// use std::ops::DerefMut;
137/// use small_derive_deref::{Deref, DerefMut};
138/// 
139/// #[derive(DerefMut, Deref)]
140/// struct WrapperStruct {
141///     field: i32,
142/// }
143///
144/// let mut w = WrapperStruct { field: 1 };
145/// *w *= 2;
146/// assert_eq!(*w.deref_mut(), 2);
147/// 
148/// #[derive(DerefMut, Deref)]
149/// struct WrapperMultipleStruct {
150///     #[DerefTarget]
151///     field1: i32,
152///     #[DerefMutTarget]
153///     field2: i32,
154/// }
155/// 
156/// let mut w = WrapperMultipleStruct { field1: 1, field2: 3 };
157/// *w *= 2;
158/// assert_eq!(*w.deref_mut(), 6);
159/// assert_eq!(*w, 1);
160/// 
161/// #[derive(DerefMut, Deref)]
162/// struct WrapperTuple(i32);
163/// 
164/// let mut w = WrapperTuple(1);
165/// *w *= 2;
166/// assert_eq!(*w.deref_mut(), 2);
167/// ```
168#[proc_macro_derive(DerefMut, attributes(DerefMutTarget))]
169pub fn derive_deref_mut(input: TokenStream) -> TokenStream {
170    let input = parse_macro_input!(input as DeriveInput);
171    let struct_name = input.ident;
172    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
173
174    let expanded = match input.data {
175        syn::Data::Struct(data_struct) => {
176            match &data_struct.fields {
177                Fields::Named(named) => {
178                    let field = match named.named.len() {
179                        1 => { named.named.first() }
180                        _ => named.named.iter()
181                        .find_map(|field| {
182                            for attr in &field.attrs {
183                                if attr.path().is_ident("DerefMutTarget") {
184                                    return Some(field);
185                                }
186                            }
187                            None
188                        })
189                    };
190
191                    if let Some(field) = field {
192                        let field_name = &field.ident;
193                        quote! {
194                            impl #impl_generics std::ops::DerefMut for #struct_name #type_generics #where_clause {
195                                fn deref_mut(&mut self) -> &mut Self::Target {
196                                    &mut self.#field_name
197                                }
198                            }
199                        }
200                    } else {
201                        panic!("No field marked with #[DerefMutTarget]")
202                    }
203                },
204                Fields::Unnamed(_) => {
205                    quote! {
206                        impl #impl_generics std::ops::DerefMut for #struct_name #type_generics #where_clause {
207                            fn deref_mut(&mut self) -> &mut Self::Target {
208                                &mut self.0
209                            }
210                        }
211                    }
212                },
213                Fields::Unit => panic!("DerefMut not implemented for unit structs"),
214            }
215        },
216        _ => panic!("DerefMut only implemented for structs"),
217    };
218
219    expanded.into()
220}