derive_getters/
lib.rs

1//! This library provides two derive macros. One, `Getters` for autogenerating getters and
2//! `Dissolve` for consuming a struct returning a tuple of all fields. They can only be
3//! used on named structs.
4//!
5//! # Derives
6//!
7//! Only named structs can derive `Getters` or `Dissolve`.
8//!
9//! # `Getter` methods generated
10//!
11//! The getter methods generated shall bear the same name as the struct fields and be
12//! publicly visible. The methods return an immutable reference to the struct field of the
13//! same name. If there is already a method defined with that name there'll be a collision.
14//! In these cases one of two attributes can be set to either `skip` or `rename` the getter.
15//! 
16//!
17//! # `Getters` Usage
18//!
19//! In lib.rs or main.rs;
20//!
21//! ```edition2018
22//! use derive_getters::Getters;
23//!
24//! #[derive(Getters)]
25//! struct Number {
26//!     num: u64,    
27//! }
28//! 
29//! let number = Number { num: 655 };
30//! assert!(number.num() == &655);
31//! ```
32//!
33//! Here, a method called `num()` has been created for the `Number` struct which gives a
34//! reference to the `num` field.
35//!
36//! This macro can also derive on structs that have simple generic types. For example;
37//!
38//! ```edition2018
39//! # use derive_getters::Getters;
40//! #[derive(Getters)]
41//! struct Generic<T, U> {
42//!     gen_t: T,
43//!     gen_u: U,
44//! }
45//! #
46//! # fn main() { }
47//! ```
48//!
49//! The macro can also handle generic types with trait bounds. For example;
50//! ```edition2018
51//! # use derive_getters::Getters;
52//! #[derive(Getters)]
53//! struct Generic<T: Clone, U: Copy> {
54//!     gen_t: T,
55//!     gen_u: U,
56//! }
57//! #
58//! # fn main() { }
59//! ```
60//! The trait bounds can also be declared in a `where` clause.
61//!
62//! Additionaly, simple lifetimes are OK too;
63//! ```edition2018
64//! # use derive_getters::Getters;
65//! #[derive(Getters)]
66//! struct Annotated<'a, 'b, T> {
67//!     stuff: &'a T,
68//!     comp: &'b str,
69//!     num: u64,
70//! }
71//! #
72//! # fn main() { }
73//! ```
74//!
75//! # `Getter` Attributes
76//! Getters can be further configured to either skip or rename a getter.
77//!
78//! * #[getter(skip)]
79//! Will skip generating a getter for the field being decorated.
80//!
81//! * #[getter(rename = "name")]
82//! Changes the name of the getter (default is the field name) to "name".
83//!
84//!```edition2018
85//! # use derive_getters::Getters;
86//! #[derive(Getters)]
87//! struct Attributed {
88//!     keep_me: u64,
89//!
90//!     #[getter(skip)]
91//!     skip_me: u64,
92//!
93//!     #[getter(rename = "number")]
94//!     rename_me: u64,
95//! }
96//! #
97//! # fn main() { }
98//! ```
99//!
100//! # `Dissolve` method generated
101//!
102//! Deriving `Dissolve` on a named struct will generate a method `dissolve(self)` which
103//! shall return a tuple of all struct fields in the order they were defined. Calling this
104//! method consumes the struct. The name of this method can be changed with an attribute.
105//!
106//! # `Dissolve` usage
107//!
108//! ```edition2018
109//! # use derive_getters::Dissolve;
110//! #[derive(Dissolve)]
111//! struct Stuff {
112//!     name: String,
113//!     price: f64,
114//!     count: usize,
115//! }
116//! 
117//! fn main() {
118//!     let stuff = Stuff {
119//!         name: "Hogie".to_owned(),
120//!         price: 123.4f64,
121//!         count: 100,
122//!     };
123//!
124//!     let (n, p, c) = stuff.dissolve();
125//!     assert!(n == "Hogie");
126//!     assert!(p == 123.4f64);
127//!     assert!(c == 100);
128//! }
129//! ```
130//!
131//! # `Dissolve` Attributes
132//! You can rename the `dissolve` function by using a struct attribute.
133//!
134//! * #[dissolve(rename = "name")]
135//!
136//! ```edition2018
137//! # use derive_getters::Dissolve;
138//! #[derive(Dissolve)]
139//! #[dissolve(rename = "shatter")]
140//! struct Numbers {
141//!     a: u64,
142//!     b: i64,
143//!     c: f64,
144//! }
145//! #
146//! # fn main() { }
147//! ```
148//!
149//! # Comment Replication/Generation
150//!
151//! Comments are produced for the auto-generated getters or dissolver. A comment is also
152//! generated for the impl block.
153//!
154//! ## Replication of comments
155//!
156//! Any field comments are replicated for the getter. If the field on the target struct
157//! has a comment; the getter for it shall have the exact same comment.
158//!
159//! ```edition2018
160//! # use derive_getters::Getters;
161//! #[derive(Getters)]
162//! struct Number {
163//!     /// My special number.
164//!     num: u64,    
165//! }
166//! #
167//! # fn main() { }
168//!```
169//!
170//! ## Generation of comments
171//!
172//! If no comment is present for the field, one shall be generated like so;
173//! " Get field `{}` from instance of `{}`."
174//!
175//! A comment for the dissolve function shall be similarily generated;
176//! "Dissolve `{}` into a tuple consisting of its fields in order of declaration."
177//!
178//! The impl block for the getters or dissolve function also has a comment generated;
179//! "Auto-generated by `derive_getters::Getters`." and or
180//! "Auto-generated by `derive_getters::Dissolve`".
181//!
182//! # Panics
183//!
184//! If `Getters` or `Dissolve` are derived on unit, unnamed structs, enums or unions.
185//!
186//! # Cannot Do
187//! Const generics aren't handled by this macro nor are they tested.
188use std::convert::TryFrom;
189
190extern crate proc_macro;
191use syn::{DeriveInput, parse_macro_input};
192
193mod faultmsg;
194mod dissolve;
195mod getters;
196mod extract;
197
198/// Generate getter methods for all named struct fields in a seperate struct `impl` block.
199/// Getter methods share the name of the field they're 'getting'. Methods return an
200/// immutable reference to the field.
201#[proc_macro_derive(Getters, attributes(getter))]
202pub fn getters(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
203    let ast = parse_macro_input!(input as DeriveInput);
204    
205    getters::NamedStruct::try_from(&ast)
206        .map(|ns| ns.emit())
207        .unwrap_or_else(|err| err.to_compile_error())
208        .into()
209}
210
211/// Produce a `dissolve` method that consumes the named struct returning a tuple of all the
212/// the struct fields.
213#[proc_macro_derive(Dissolve, attributes(dissolve))]
214pub fn dissolve(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
215    let ast = parse_macro_input!(input as DeriveInput);
216
217    dissolve::NamedStruct::try_from(&ast)
218        .map(|ns| ns.emit())
219        .unwrap_or_else(|err| err.to_compile_error())
220        .into()
221}