getset/
lib.rs

1/*!
2Getset, we're ready to go!
3
4A procedural macro for generating the most basic getters and setters on fields.
5
6Getters are generated as `fn field(&self) -> &type`, while setters are generated as `fn field(&mut self, val: type)`.
7
8These macros are not intended to be used on fields which require custom logic inside of their setters and getters. Just write your own in that case!
9
10```rust
11use getset::{CopyGetters, Getters, MutGetters, Setters};
12
13#[derive(Getters, Setters, MutGetters, CopyGetters, Default)]
14pub struct Foo<T>
15where
16    T: Copy + Clone + Default,
17{
18    /// Doc comments are supported!
19    /// Multiline, even.
20    #[getset(get, set, get_mut)]
21    private: T,
22
23    /// Doc comments are supported!
24    /// Multiline, even.
25    #[getset(get_copy = "pub", set = "pub", get_mut = "pub")]
26    public: T,
27}
28
29let mut foo = Foo::default();
30foo.set_private(1);
31(*foo.private_mut()) += 1;
32assert_eq!(*foo.private(), 2);
33```
34
35You can use `cargo-expand` to generate the output. Here are the functions that the above generates (Replicate with `cargo expand --example simple`):
36
37```rust,ignore
38use getset::{Getters, MutGetters, CopyGetters, Setters};
39pub struct Foo<T>
40where
41    T: Copy + Clone + Default,
42{
43    /// Doc comments are supported!
44    /// Multiline, even.
45    #[getset(get, get, get_mut)]
46    private: T,
47    /// Doc comments are supported!
48    /// Multiline, even.
49    #[getset(get_copy = "pub", set = "pub", get_mut = "pub")]
50    public: T,
51}
52impl<T> Foo<T>
53where
54    T: Copy + Clone + Default,
55{
56    /// Doc comments are supported!
57    /// Multiline, even.
58    #[inline(always)]
59    fn private(&self) -> &T {
60        &self.private
61    }
62}
63impl<T> Foo<T>
64where
65    T: Copy + Clone + Default,
66{
67    /// Doc comments are supported!
68    /// Multiline, even.
69    #[inline(always)]
70    pub fn set_public(&mut self, val: T) -> &mut Self {
71        self.public = val;
72        self
73    }
74}
75impl<T> Foo<T>
76where
77    T: Copy + Clone + Default,
78{
79    /// Doc comments are supported!
80    /// Multiline, even.
81    #[inline(always)]
82    fn private_mut(&mut self) -> &mut T {
83        &mut self.private
84    }
85    /// Doc comments are supported!
86    /// Multiline, even.
87    #[inline(always)]
88    pub fn public_mut(&mut self) -> &mut T {
89        &mut self.public
90    }
91}
92impl<T> Foo<T>
93where
94    T: Copy + Clone + Default,
95{
96    /// Doc comments are supported!
97    /// Multiline, even.
98    #[inline(always)]
99    pub fn public(&self) -> T {
100        self.public
101    }
102}
103```
104
105Attributes can be set on struct level for all fields in struct as well. Field level attributes take
106precedence.
107
108```rust
109mod submodule {
110    use getset::{Getters, MutGetters, CopyGetters, Setters};
111    #[derive(Getters, CopyGetters, Default)]
112    #[getset(get_copy = "pub")] // By default add a pub getting for all fields.
113    pub struct Foo {
114        public: i32,
115        #[getset(get_copy)] // Override as private
116        private: i32,
117    }
118    fn demo() {
119        let mut foo = Foo::default();
120        foo.private();
121    }
122}
123
124let mut foo = submodule::Foo::default();
125foo.public();
126```
127
128For some purposes, it's useful to have the `get_` prefix on the getters for
129either legacy of compatibility reasons. It is done with `with_prefix`.
130
131```rust
132use getset::{Getters, MutGetters, CopyGetters, Setters};
133
134#[derive(Getters, Default)]
135pub struct Foo {
136    #[getset(get = "pub with_prefix")]
137    field: bool,
138}
139
140
141let mut foo = Foo::default();
142let val = foo.get_field();
143```
144
145Skipping setters and getters generation for a field when struct level attribute is used
146is possible with `#[getset(skip)]`.
147
148```rust
149use getset::{CopyGetters, Setters};
150
151#[derive(CopyGetters, Setters)]
152#[getset(get_copy, set)]
153pub struct Foo {
154    // If the field was not skipped, the compiler would complain about moving
155    // a non-copyable type in copy getter.
156    #[getset(skip)]
157    skipped: String,
158
159    field1: usize,
160    field2: usize,
161}
162
163impl Foo {
164    // It is possible to write getters and setters manually,
165    // possibly with a custom logic.
166    fn skipped(&self) -> &str {
167        &self.skipped
168    }
169
170    fn set_skipped(&mut self, val: &str) -> &mut Self {
171        self.skipped = val.to_string();
172        self
173    }
174}
175```
176*/
177
178#[macro_use]
179extern crate quote;
180
181use proc_macro::TokenStream;
182use proc_macro2::TokenStream as TokenStream2;
183use proc_macro_error2::{abort, abort_call_site, proc_macro_error};
184use syn::{parse_macro_input, spanned::Spanned, DataStruct, DeriveInput, Meta};
185
186use crate::generate::{GenMode, GenParams};
187
188mod generate;
189
190#[proc_macro_derive(Getters, attributes(get, with_prefix, getset))]
191#[proc_macro_error]
192pub fn getters(input: TokenStream) -> TokenStream {
193    let ast = parse_macro_input!(input as DeriveInput);
194    let params = GenParams {
195        mode: GenMode::Get,
196        global_attr: parse_global_attr(&ast.attrs, GenMode::Get),
197    };
198
199    produce(&ast, &params).into()
200}
201
202#[proc_macro_derive(CopyGetters, attributes(get_copy, with_prefix, getset))]
203#[proc_macro_error]
204pub fn copy_getters(input: TokenStream) -> TokenStream {
205    let ast = parse_macro_input!(input as DeriveInput);
206    let params = GenParams {
207        mode: GenMode::GetCopy,
208        global_attr: parse_global_attr(&ast.attrs, GenMode::GetCopy),
209    };
210
211    produce(&ast, &params).into()
212}
213
214#[proc_macro_derive(MutGetters, attributes(get_mut, getset))]
215#[proc_macro_error]
216pub fn mut_getters(input: TokenStream) -> TokenStream {
217    let ast = parse_macro_input!(input as DeriveInput);
218    let params = GenParams {
219        mode: GenMode::GetMut,
220        global_attr: parse_global_attr(&ast.attrs, GenMode::GetMut),
221    };
222
223    produce(&ast, &params).into()
224}
225
226#[proc_macro_derive(Setters, attributes(set, getset))]
227#[proc_macro_error]
228pub fn setters(input: TokenStream) -> TokenStream {
229    let ast = parse_macro_input!(input as DeriveInput);
230    let params = GenParams {
231        mode: GenMode::Set,
232        global_attr: parse_global_attr(&ast.attrs, GenMode::Set),
233    };
234
235    produce(&ast, &params).into()
236}
237
238fn parse_global_attr(attrs: &[syn::Attribute], mode: GenMode) -> Option<Meta> {
239    attrs.iter().filter_map(|v| parse_attr(v, mode)).last()
240}
241
242fn parse_attr(attr: &syn::Attribute, mode: GenMode) -> Option<syn::Meta> {
243    use syn::{punctuated::Punctuated, Token};
244
245    if attr.path().is_ident("getset") {
246        let meta_list =
247            match attr.parse_args_with(Punctuated::<syn::Meta, Token![,]>::parse_terminated) {
248                Ok(list) => list,
249                Err(e) => abort!(attr.span(), "Failed to parse getset attribute: {}", e),
250            };
251
252        let (last, skip, mut collected) = meta_list
253            .into_iter()
254            .inspect(|meta| {
255                if !(meta.path().is_ident("get")
256                    || meta.path().is_ident("get_copy")
257                    || meta.path().is_ident("get_mut")
258                    || meta.path().is_ident("set")
259                    || meta.path().is_ident("skip"))
260                {
261                    abort!(meta.path().span(), "unknown setter or getter")
262                }
263            })
264            .fold(
265                (None, None, Vec::new()),
266                |(last, skip, mut collected), meta| {
267                    if meta.path().is_ident(mode.name()) {
268                        (Some(meta), skip, collected)
269                    } else if meta.path().is_ident("skip") {
270                        (last, Some(meta), collected)
271                    } else {
272                        collected.push(meta);
273                        (last, skip, collected)
274                    }
275                },
276            );
277
278        if skip.is_some() {
279            // Check if there is any setter or getter used with skip, which is
280            // forbidden.
281            if last.is_none() && collected.is_empty() {
282                skip
283            } else {
284                abort!(
285                    last.or_else(|| collected.pop()).unwrap().path().span(),
286                    "use of setters and getters with skip is invalid"
287                );
288            }
289        } else {
290            last
291        }
292    } else if attr.path().is_ident(mode.name()) {
293        // If skip is not used, return the last occurrence of matching
294        // setter/getter, if there is any.
295        attr.meta.clone().into()
296    } else {
297        None
298    }
299}
300
301fn produce(ast: &DeriveInput, params: &GenParams) -> TokenStream2 {
302    let name = &ast.ident;
303    let generics = &ast.generics;
304    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
305
306    // Is it a struct?
307    if let syn::Data::Struct(DataStruct { ref fields, .. }) = ast.data {
308        let generated = fields.iter().map(|f| generate::implement(f, params));
309
310        quote! {
311            impl #impl_generics #name #ty_generics #where_clause {
312                #(#generated)*
313            }
314        }
315    } else {
316        // Nope. This is an Enum. We cannot handle these!
317        abort_call_site!("#[derive(Getters)] is only defined for structs, not for enums!");
318    }
319}