getters_by_type/
lib.rs

1//!
2//! This crate provides [`GettersByType`](derive.GettersByType.html) derive macro for structs, which implements a getter method for each type they contain.
3//!
4//! The generated methods start with the prefix `get_fields_` and end with a transcription of the type they refer.
5//!
6//! Example using `GettersByType` :
7//!
8//! ```rust
9//! use getters_by_type::GettersByType;
10//! #[derive(GettersByType)]
11//! struct Foo {
12//!     first: i32,
13//!     second: i32,
14//!     third: i32,
15//! }
16//!
17//! let object = Foo { first: 6, second: 12, third: 24 };
18//!
19//! // Let's sum all the i32 fields with a fold expression:
20//! assert_eq!(object.get_fields_i32().iter().fold(0, |acc, x| **x + acc), 42);
21//! ```
22//!
23//! As you notice, the getter methods return an array containing references to all the fields of the same type.
24//! In that example, the return type of the method `get_fields_i32` would be `[&i32; 3]`.
25//!
26//! This crate also provides a `mut` version [`GettersMutByType`](derive.GettersMutByType.html) which also adds a mut version for those methods.
27//!
28//! In this case, the generated methods start with the prefix `get_mut_fields_` instead.
29//!
30//! Example using `GettersMutByType` :
31//!
32//!
33//! ```rust
34//! use getters_by_type::GettersMutByType;
35//!
36//! #[derive(Default)]
37//! struct Updater {}
38//! impl Updater {
39//!     fn update(&mut self) {/*...*/}
40//! }
41//!
42//! #[derive(GettersMutByType, Default)]
43//! struct Foo {
44//!     first: Updater,
45//!     second: Updater,
46//!     /*...*/
47//!     onehundredth: Updater,
48//! }
49//!
50//! let mut object = Foo::default();
51//!
52//! // Let's update all the Updater fields
53//! for updater in object.get_mut_fields_updater().iter_mut() {
54//!     updater.update();
55//! }
56//! ```
57//!
58//! In this example, the return type of the method `get_mut_fields_updater` would be `[&mut Updater; 3]`.
59//! There is no dynamic memory allocation happening within the getter methods, as they just return a fixed array with references.
60//! There isn't also unsafe code being generated.
61//! For more documentation and examples, see each respective documentation section.
62
63extern crate proc_macro;
64
65use proc_macro::TokenStream;
66use proc_macro2::{Span, TokenTree};
67use quote::quote;
68use std::collections::HashMap;
69
70/// The `GettersByType` macro automatically generates an `impl` for the given struct,
71/// implementing a getter method for each different type contained within the struct.
72///
73/// The generated methods start with the prefix `get_fields_` and end with a transcription of the type they refer.
74///
75/// Example:
76///
77/// ```rust
78/// use getters_by_type::GettersByType;
79/// #[derive(GettersByType)]
80/// struct Foo {
81///     a: String,
82///     b: String,
83/// }
84///
85/// // Would generete:
86///
87/// impl Foo {
88///     fn get_fields_string(&self) -> [&String; 2] {
89///         [&self.a, &self.b]
90///     }
91/// }
92/// ```
93///
94/// As you notice, the chars of all the types (`String` in this case) go
95/// to the method signature in lowercase form.
96///
97/// It works the same with generic, reference and other types, with the following exceptions:
98/// 1. Characters `<` `>` `(` `)` `[` `]` `,` `;` always get converted to `_`.
99/// 2. Return type arrow `->` and reference character `&` get ignored completely.
100/// 3. Pointer types `*const` and `*mut` get converted o `ptr_const_` and `ptr_mut_` respectively.
101///
102/// Also, reference types and non-reference types will be covered by the same
103/// method, as the methods are always returning references in the first place.
104///
105/// Example for fn, generic and reference types (more examples for other types later):
106///
107/// ```rust
108/// use getters_by_type::GettersByType;
109/// #[derive(GettersByType)]
110/// struct Foo {
111///     a: Result<i32, i32>,
112///     b: Result<i32, Result<i32, i32>>,
113///     c: fn(usize) -> f32,
114///     d: &'static bool,
115///     e: bool,
116/// }
117///
118/// // Would generate:
119///
120/// impl Foo {
121///     fn get_fields_result_i32_i32_(&self) -> [&Result<i32, i32>; 1] {
122///         [&self.a]
123///     }
124///     fn get_fields_result_i32_result_i32_i32__(&self) -> [&Result<i32, Result<i32, i32>>; 1] {
125///         [&self.b]
126///     }
127///     fn get_fields_fn_usize___f32(&self) -> [&fn(usize) -> f32; 1] {
128///         [&self.c]
129///     }
130///     fn get_fields_bool(&self) -> [&bool; 2] {
131///         [&self.d, &self.e]
132///     }
133/// }
134/// ```
135///
136/// Other examples of types to method signature conversions here:
137///
138/// ```rust
139/// use getters_by_type::GettersByType;
140/// #[derive(GettersByType)]
141/// struct Foo<'a> {
142///     a: &'a str,
143///     b: Box<Fn(i32) -> f32>,
144///     c: &'a Vec<&'a Option<&'a i32>>,
145///     d: Result<i32, Result<i32, Result<i32, &'static str>>>,
146///     e: Option<Option<Option<Option<Option<fn(usize)>>>>>,
147///     f: (i32, i32),
148///     g: [i32; 2],
149///     h: &'a [&'a Option<&'a i32>],
150///     i: *const i32,
151///     j: *mut i32,
152///     k: Box<dyn Bar>,
153/// }
154/// trait Bar {}
155/// impl Bar for i32 {}
156/// let vector = vec!();
157/// let number_1 = 1;
158/// let mut number_2 = 2;
159/// let o = Foo {
160///     a: "",
161///     b: Box::new(|_| 0.0),
162///     c: &vector,
163///     d: Ok(0),
164///     e: None,
165///     f: (0, 0),
166///     g: [0, 0],
167///     h: vector.as_slice(),
168///     i: &number_1,
169///     j: &mut number_2,
170///     k: Box::new(0),
171/// };
172/// // from type: &'a str
173/// o.get_fields_str();
174/// // from type: Box<Fn(i32) -> f32>
175/// o.get_fields_box_fn_i32_f32_();
176/// // from type: &'a Vec<&'a Option<&'a i32>>
177/// o.get_fields_vec_option_i32__();
178/// // from type: Result<i32, Result<i32, Result<i32, &'static str>>>
179/// o.get_fields_result_i32_result_i32_result_i32_str___();
180/// // from type: Option<Option<Option<Option<Option<fn(usize)>>>>>
181/// o.get_fields_option_option_option_option_option_fn_usize______();
182/// // from type: (i32, i32)
183/// o.get_fields__i32_i32_();
184/// // from type: [i32; 2]
185/// o.get_fields__i32_2_();
186/// // from type: &'a [&'a Option<&'a i32>]
187/// o.get_fields__option_i32__();
188/// // from type: *const i32
189/// o.get_fields_ptr_const_i32();
190/// // from type: *mut i32
191/// o.get_fields_ptr_mut_i32();
192/// // from type: Box<dyn Bar>
193/// o.get_fields_box_dyn_bar_();
194/// ```
195///
196/// Method visibility is inherited directly from the struct visibility,
197/// so if the struct is public, all the methods generated by `GettersByType`
198/// will be public too. There is no fine-grained control for fields visibility.
199///
200/// There are still some types not implemented. Those are the following:
201///
202/// * `TraitObject` is partially implemented, `Box<dyn Trait>` works, but `&dyn Trait` doesn't.
203/// * `Never`
204/// * `ImplTrait`
205/// * `Group`
206/// * `Infer`
207/// * `Macro`
208/// * `Verbatim`
209///
210/// Hopefully, they will get implemented in next releases.
211///
212#[proc_macro_derive(GettersByType)]
213pub fn getters_by_type(input: TokenStream) -> TokenStream {
214    ImplContext::new(input, "GettersByType", false).transform_ast()
215}
216
217/// The `GettersMutByType` macro automatically generates an `impl` for the given struct,
218/// implementing a getter method for each different type contained within the struct.
219///
220/// The generated methods start with the prefix `get_mut_fields_` and end with a transcription of the type they refer.
221///
222/// Example:
223///
224/// ```rust
225/// use getters_by_type::GettersMutByType;
226/// #[derive(GettersMutByType)]
227/// struct Foo {
228///     a: String,
229///     b: String,
230/// }
231///
232/// // Would generete:
233///
234/// impl Foo {
235///     fn get_mut_fields_string(&mut self) -> [&mut String; 2] {
236///         [&mut self.a, &mut self.b]
237///     }
238/// }
239/// ```
240///
241/// This is the mutable version of `GettersByType`.
242/// The same rules are applying, so check the [GettersByType derive](derive.GettersByType.html) documentation first.
243///
244/// There is one important difference, thought. There are some fields with types that
245/// can't be made mutable. I.e. types with immutable references. When that's the case,
246/// the field gets ignored completely.
247///
248/// Example:
249///
250/// ```rust
251/// use getters_by_type::GettersMutByType;
252/// #[derive(GettersMutByType)]
253/// struct Foo<'a> {
254///     a: &'a String,
255///     b: String,
256/// }
257///
258/// let string = String::new();
259/// let mut o = Foo {
260///     a: &string,
261///     b: "".into(),
262/// };
263///
264/// assert_eq!(o.get_mut_fields_string().len(), 1); // instead of 2
265/// ```
266#[proc_macro_derive(GettersMutByType)]
267pub fn getters_mut_by_type(input: TokenStream) -> TokenStream {
268    ImplContext::new(input, "GettersByMutType", true).transform_ast()
269}
270
271struct ImplContext {
272    ast: syn::DeriveInput,
273    derive_name: &'static str,
274    with_mutability: bool,
275}
276
277impl ImplContext {
278    fn new(input: TokenStream, derive_name: &'static str, with_mutability: bool) -> ImplContext {
279        ImplContext {
280            ast: syn::parse(input).expect("Could not parse AST."),
281            derive_name,
282            with_mutability,
283        }
284    }
285
286    fn transform_ast(&self) -> TokenStream {
287        let fields_by_type = match self.ast.data {
288            syn::Data::Struct(ref class) => self.read_fields(&class.fields),
289            _ => panic!(
290                "The type '{}' is not a struct but tries to derive '{}' which can only be used on structs.",
291                self.ast.ident, self.derive_name
292            ),
293        };
294        let mut methods = Vec::<TokenTree>::new();
295        for (type_pieces, fields_sharing_type) in fields_by_type.into_iter() {
296            let return_type = MethodReturnType {
297                ty: fields_sharing_type.ty,
298                name: make_type_name_from_type_pieces(type_pieces),
299            };
300            methods.extend(self.make_method_tokens("get_fields", &return_type, false, fields_sharing_type.immutable_fields));
301            if self.with_mutability {
302                methods.extend(self.make_method_tokens("get_mut_fields", &return_type, true, fields_sharing_type.mutable_fields));
303            }
304        }
305        let (ty, generics) = (&self.ast.ident, &self.ast.generics);
306        let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
307        let tokens = quote! {
308            impl #impl_generics #ty #ty_generics
309                #where_clause
310            {
311                #(#methods)
312                *
313            }
314        };
315        tokens.into()
316    }
317
318    fn read_fields<'a>(&self, fields: &'a syn::Fields) -> HashMap<Vec<TypePart<'a>>, FieldsSharingType<'a>> {
319        let mut fields_by_type = HashMap::<Vec<TypePart>, FieldsSharingType>::new();
320        for field in fields.iter() {
321            if let Some(ref ident) = field.ident {
322                let info = get_info_from_type(&field.ty);
323                match make_idents_from_type(&field.ty) {
324                    Ok(type_pieces) => {
325                        let fields_by_type = fields_by_type.entry(type_pieces).or_insert_with(|| FieldsSharingType::new(info.ty));
326                        if info.is_mutable && self.with_mutability {
327                            fields_by_type.mutable_fields.push(ident);
328                        }
329                        fields_by_type.immutable_fields.push(ident);
330                    }
331                    Err(err) => {
332                        eprintln!("[WARNING::{}] Field '{}' of struct '{}' not covered because: {}", self.derive_name, ident, self.ast.ident, err);
333                    }
334                }
335            }
336        }
337        fields_by_type
338    }
339
340    fn make_method_tokens(&self, method_prefix: &str, return_type: &MethodReturnType, mutability: bool, field_idents: Vec<&syn::Ident>) -> proc_macro2::TokenStream {
341        let count = field_idents.len();
342        let method_name = syn::Ident::new(&format!("{}_{}", method_prefix, return_type.name), Span::call_site());
343        let (vis, return_type) = (&self.ast.vis, &return_type.ty);
344        if mutability {
345            quote! {
346                #vis fn #method_name(&mut self) -> [&mut #return_type; #count] {
347                    [#(&mut self.#field_idents),*]
348                }
349            }
350        } else {
351            quote! {
352                #vis fn #method_name(&self) -> [&#return_type; #count] {
353                    [#(&self.#field_idents),*]
354                }
355            }
356        }
357    }
358}
359
360struct MethodReturnType<'a> {
361    ty: &'a syn::Type,
362    name: String,
363}
364
365struct FieldsSharingType<'a> {
366    immutable_fields: Vec<&'a syn::Ident>,
367    mutable_fields: Vec<&'a syn::Ident>,
368    ty: &'a syn::Type,
369}
370
371impl<'a> FieldsSharingType<'a> {
372    fn new(ty: &'a syn::Type) -> FieldsSharingType {
373        FieldsSharingType {
374            immutable_fields: vec![],
375            mutable_fields: vec![],
376            ty,
377        }
378    }
379}
380
381struct TypeInfo<'a> {
382    is_mutable: bool,
383    ty: &'a syn::Type,
384}
385
386#[derive(Hash, PartialEq, Eq)]
387enum TypePart<'a> {
388    Ident(&'a syn::Ident),
389    Integer(u64),
390    Separator(&'static str),
391}
392
393impl<'a> TypePart<'a> {
394    fn to_string(&self) -> String {
395        match self {
396            TypePart::Ident(i) => i.to_string(),
397            TypePart::Separator(s) => s.to_string(),
398            TypePart::Integer(i) => i.to_string(),
399        }
400    }
401}
402
403fn get_info_from_type(ty: &syn::Type) -> TypeInfo {
404    let (ty, is_mutable) = match ty {
405        syn::Type::Reference(ref reference) => (&*reference.elem, reference.mutability.is_some()),
406        _ => (ty, true),
407    };
408    TypeInfo { is_mutable, ty }
409}
410
411fn make_idents_from_type<'a>(ty: &'a syn::Type) -> Result<Vec<TypePart<'a>>, &'static str> {
412    let mut type_pieces = Vec::<TypePart<'a>>::with_capacity(8);
413    fill_type_pieces_from_type(&mut type_pieces, ty)?;
414    Ok(type_pieces)
415}
416
417fn fill_type_pieces_from_type<'a>(type_pieces: &mut Vec<TypePart<'a>>, ty: &'a syn::Type) -> Result<(), &'static str> {
418    match ty {
419        syn::Type::Path(ref path) => fill_type_pieces_from_type_path(type_pieces, &path.path),
420        syn::Type::Reference(ref reference) => fill_type_pieces_from_type(type_pieces, &reference.elem),
421        syn::Type::BareFn(ref function) => {
422            type_pieces.push(TypePart::Separator("fn("));
423            fill_type_pieces_from_array_of_inputs(type_pieces, &function.inputs, ",", |type_pieces, arg| fill_type_pieces_from_type(type_pieces, &arg.ty))?;
424            type_pieces.push(TypePart::Separator(")"));
425            fill_type_pieces_from_return_type(type_pieces, &function.output)?;
426            Ok(())
427        }
428        syn::Type::Slice(slice) => {
429            type_pieces.push(TypePart::Separator("["));
430            fill_type_pieces_from_type(type_pieces, &slice.elem)?;
431            type_pieces.push(TypePart::Separator("]"));
432            Ok(())
433        }
434        syn::Type::Array(array) => {
435            type_pieces.push(TypePart::Separator("["));
436            fill_type_pieces_from_type(type_pieces, &array.elem)?;
437            type_pieces.push(TypePart::Separator(";"));
438            match &array.len {
439                syn::Expr::Lit(lit) => match &lit.lit {
440                    syn::Lit::Int(int) => type_pieces.push(TypePart::Integer(int.value())),
441                    _ => return Err("syn::Lit::* are not implemented yet."),
442                },
443                _ => return Err("syn::Expr::* are not implemented yet."),
444            }
445            type_pieces.push(TypePart::Separator("]"));
446            Ok(())
447        }
448        syn::Type::Tuple(tuple) => {
449            type_pieces.push(TypePart::Separator("("));
450            fill_type_pieces_from_array_of_inputs(type_pieces, &tuple.elems, ",", fill_type_pieces_from_type)?;
451            type_pieces.push(TypePart::Separator(")"));
452            Ok(())
453        }
454        syn::Type::Paren(paren) => {
455            type_pieces.push(TypePart::Separator("("));
456            fill_type_pieces_from_type(type_pieces, &paren.elem)?;
457            type_pieces.push(TypePart::Separator(")"));
458            Ok(())
459        }
460        syn::Type::Ptr(ptr) => {
461            type_pieces.push(TypePart::Separator("ptr_"));
462            if ptr.const_token.is_some() {
463                type_pieces.push(TypePart::Separator("const_"));
464            }
465            if ptr.mutability.is_some() {
466                type_pieces.push(TypePart::Separator("mut_"));
467            }
468            fill_type_pieces_from_type(type_pieces, &ptr.elem)?;
469            Ok(())
470        }
471        syn::Type::ImplTrait(_) => Err("syn::Type::ImplTrait can not be implemented."), // ImplTrait is not valid outside of functions and inherent return types, so can't be implemented.
472        syn::Type::TraitObject(trait_object) => {
473            if trait_object.dyn_token.is_some() {
474                type_pieces.push(TypePart::Separator("dyn_"));
475            }
476            fill_type_pieces_from_array_of_inputs(type_pieces, &trait_object.bounds, "+", |type_pieces, bound| match bound {
477                syn::TypeParamBound::Trait(trait_bound) => fill_type_pieces_from_type_path(type_pieces, &trait_bound.path),
478                syn::TypeParamBound::Lifetime(_) => Ok(()),
479            })
480        }
481        syn::Type::Never(_) => Err("syn::Type::Never is not implemented yet."),
482        syn::Type::Group(_) => Err("syn::Type::Group is not implemented yet."),
483        syn::Type::Infer(_) => Err("syn::Type::Infer is not implemented yet."),
484        syn::Type::Macro(_) => Err("syn::Type::Macro is not implemented yet."),
485        syn::Type::Verbatim(_) => Err("syn::Type::Verbatim is not implemented yet."),
486    }
487}
488
489fn fill_type_pieces_from_type_path<'a>(type_pieces: &mut Vec<TypePart<'a>>, path: &'a syn::Path) -> Result<(), &'static str> {
490    for segment in path.segments.iter() {
491        type_pieces.push(TypePart::Ident(&segment.ident));
492        fill_type_pieces_from_path_arguments(type_pieces, &segment.arguments)?;
493    }
494    Ok(())
495}
496
497fn fill_type_pieces_from_path_arguments<'a>(type_pieces: &mut Vec<TypePart<'a>>, arguments: &'a syn::PathArguments) -> Result<(), &'static str> {
498    match arguments {
499        syn::PathArguments::AngleBracketed(ref angle) => {
500            type_pieces.push(TypePart::Separator("<"));
501            fill_type_pieces_from_array_of_inputs(type_pieces, &angle.args, ",", |type_pieces, arg| match arg {
502                syn::GenericArgument::Type(ref ty) => fill_type_pieces_from_type(type_pieces, ty),
503                syn::GenericArgument::Lifetime(_) => Ok(()),
504                syn::GenericArgument::Binding(_) => Ok(()),
505                syn::GenericArgument::Constraint(_) => Ok(()),
506                syn::GenericArgument::Const(_) => Ok(()),
507            })?;
508            type_pieces.push(TypePart::Separator(">"));
509        }
510        syn::PathArguments::None => {}
511        syn::PathArguments::Parenthesized(ref paren) => {
512            type_pieces.push(TypePart::Separator("("));
513            fill_type_pieces_from_array_of_inputs(type_pieces, &paren.inputs, ",", fill_type_pieces_from_type)?;
514            type_pieces.push(TypePart::Separator(")"));
515            fill_type_pieces_from_return_type(type_pieces, &paren.output)?;
516        }
517    }
518    Ok(())
519}
520
521fn fill_type_pieces_from_return_type<'a>(type_pieces: &mut Vec<TypePart<'a>>, output: &'a syn::ReturnType) -> Result<(), &'static str> {
522    match output {
523        syn::ReturnType::Default => Ok(()),
524        syn::ReturnType::Type(_, ref arg) => fill_type_pieces_from_type(type_pieces, &**arg),
525    }
526}
527
528fn fill_type_pieces_from_array_of_inputs<'a, T, U>(
529    type_pieces: &mut Vec<TypePart<'a>>,
530    inputs: &'a syn::punctuated::Punctuated<T, U>,
531    separator: &'static str,
532    action: impl Fn(&mut Vec<TypePart<'a>>, &'a T) -> Result<(), &'static str>,
533) -> Result<(), &'static str> {
534    if !inputs.is_empty() {
535        for arg in inputs {
536            action(type_pieces, arg)?;
537            match type_pieces[type_pieces.len() - 1] {
538                TypePart::Separator(_s) if _s == separator => {}
539                _ => type_pieces.push(TypePart::Separator(separator)),
540            }
541        }
542        match type_pieces[type_pieces.len() - 1] {
543            TypePart::Separator(_s) if _s == separator => type_pieces.truncate(type_pieces.len() - 1),
544            _ => {}
545        }
546    }
547    Ok(())
548}
549
550fn make_type_name_from_type_pieces(type_pieces: Vec<TypePart>) -> String {
551    type_pieces
552        .into_iter()
553        .map(|piece| piece.to_string())
554        .collect::<String>()
555        .to_lowercase()
556        .chars()
557        .map(|c| match c {
558            '<' | '>' | '(' | ')' | '[' | ']' | '-' | ',' | ';' => '_',
559            _ => c,
560        })
561        .collect()
562}