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 std::sync::Arc;
12
13use getset::{CloneGetters, CopyGetters, Getters, MutGetters, Setters, WithSetters};
14
15#[derive(Getters, Setters, WithSetters, MutGetters, CopyGetters, CloneGetters, Default)]
16pub struct Foo<T>
17where
18    T: Copy + Clone + Default,
19{
20    /// Doc comments are supported!
21    /// Multiline, even.
22    #[getset(get, set, get_mut, set_with)]
23    private: T,
24
25    /// Doc comments are supported!
26    /// Multiline, even.
27    #[getset(get_copy = "pub", set = "pub", get_mut = "pub", set_with = "pub")]
28    public: T,
29
30    /// Arc supported through CloneGetters
31    #[getset(get_clone = "pub", set = "pub", get_mut = "pub", set_with = "pub")]
32    arc: Arc<u16>,
33}
34```
35
36You can use `cargo-expand` to generate the output. Here are the functions that the above generates (Replicate with `cargo expand --example simple`):
37
38```rust,ignore
39use std::sync::Arc;
40use getset::{CloneGetters, CopyGetters, Getters, MutGetters, Setters, WithSetters};
41pub struct Foo<T>
42where
43    T: Copy + Clone + Default,
44{
45    /// Doc comments are supported!
46    /// Multiline, even.
47    #[getset(get, set, get_mut, set_with)]
48    private: T,
49    /// Doc comments are supported!
50    /// Multiline, even.
51    #[getset(get_copy = "pub", set = "pub", get_mut = "pub", set_with = "pub")]
52    public: T,
53    /// Arc supported through CloneGetters
54    #[getset(get_clone = "pub", set = "pub", get_mut = "pub", set_with = "pub")]
55    arc: Arc<u16>,
56}
57impl<T> Foo<T>
58where
59    T: Copy + Clone + Default,
60{
61    /// Doc comments are supported!
62    /// Multiline, even.
63    #[inline(always)]
64    fn private(&self) -> &T {
65        &self.private
66    }
67}
68impl<T> Foo<T>
69where
70    T: Copy + Clone + Default,
71{
72    /// Doc comments are supported!
73    /// Multiline, even.
74    #[inline(always)]
75    fn set_private(&mut self, val: T) -> &mut Self {
76        self.private = val;
77        self
78    }
79    /// Doc comments are supported!
80    /// Multiline, even.
81    #[inline(always)]
82    pub fn set_public(&mut self, val: T) -> &mut Self {
83        self.public = val;
84        self
85    }
86    /// Arc supported through CloneGetters
87    #[inline(always)]
88    pub fn set_arc(&mut self, val: Arc<u16>) -> &mut Self {
89        self.arc = val;
90        self
91    }
92}
93impl<T> Foo<T>
94where
95    T: Copy + Clone + Default,
96{
97    /// Doc comments are supported!
98    /// Multiline, even.
99    #[inline(always)]
100    fn with_private(mut self, val: T) -> Self {
101        self.private = val;
102        self
103    }
104    /// Doc comments are supported!
105    /// Multiline, even.
106    #[inline(always)]
107    pub fn with_public(mut self, val: T) -> Self {
108        self.public = val;
109        self
110    }
111    /// Arc supported through CloneGetters
112    #[inline(always)]
113    pub fn with_arc(mut self, val: Arc<u16>) -> Self {
114        self.arc = val;
115        self
116    }
117}
118impl<T> Foo<T>
119where
120    T: Copy + Clone + Default,
121{
122    /// Doc comments are supported!
123    /// Multiline, even.
124    #[inline(always)]
125    fn private_mut(&mut self) -> &mut T {
126        &mut self.private
127    }
128    /// Doc comments are supported!
129    /// Multiline, even.
130    #[inline(always)]
131    pub fn public_mut(&mut self) -> &mut T {
132        &mut self.public
133    }
134    /// Arc supported through CloneGetters
135    #[inline(always)]
136    pub fn arc_mut(&mut self) -> &mut Arc<u16> {
137        &mut self.arc
138    }
139}
140impl<T> Foo<T>
141where
142    T: Copy + Clone + Default,
143{
144    /// Doc comments are supported!
145    /// Multiline, even.
146    #[inline(always)]
147    pub fn public(&self) -> T {
148        self.public
149    }
150}
151impl<T> Foo<T>
152where
153    T: Copy + Clone + Default,
154{
155    /// Arc supported through CloneGetters
156    #[inline(always)]
157    pub fn arc(&self) -> Arc<u16> {
158        self.arc.clone()
159    }
160}
161```
162
163Attributes can be set on struct level for all fields in struct as well. Field level attributes take
164precedence.
165
166```rust
167mod submodule {
168    use getset::{Getters, MutGetters, CopyGetters, Setters, WithSetters};
169    #[derive(Getters, CopyGetters, Default)]
170    #[getset(get_copy = "pub")] // By default add a pub getting for all fields.
171    pub struct Foo {
172        public: i32,
173        #[getset(get_copy)] // Override as private
174        private: i32,
175    }
176    fn demo() {
177        let mut foo = Foo::default();
178        foo.private();
179    }
180}
181
182let mut foo = submodule::Foo::default();
183foo.public();
184```
185
186For some purposes, it's useful to have the `get_` prefix on the getters for
187either legacy of compatibility reasons. It is done with `with_prefix`.
188
189```rust
190use getset::{Getters, MutGetters, CopyGetters, Setters, WithSetters};
191
192#[derive(Getters, Default)]
193pub struct Foo {
194    #[getset(get = "pub with_prefix")]
195    field: bool,
196}
197
198
199let mut foo = Foo::default();
200let val = foo.get_field();
201```
202
203Skipping setters and getters generation for a field when struct level attribute is used
204is possible with `#[getset(skip)]`.
205
206```rust
207use getset::{CopyGetters, Setters, WithSetters};
208
209#[derive(CopyGetters, Setters, WithSetters)]
210#[getset(get_copy, set, set_with)]
211pub struct Foo {
212    // If the field was not skipped, the compiler would complain about moving
213    // a non-copyable type in copy getter.
214    #[getset(skip)]
215    skipped: String,
216
217    field1: usize,
218    field2: usize,
219}
220
221impl Foo {
222    // It is possible to write getters and setters manually,
223    // possibly with a custom logic.
224    fn skipped(&self) -> &str {
225        &self.skipped
226    }
227
228    fn set_skipped(&mut self, val: &str) -> &mut Self {
229        self.skipped = val.to_string();
230        self
231    }
232
233    fn with_skipped(mut self, val: &str) -> Self {
234        self.skipped = val.to_string();
235        self
236    }
237}
238```
239
240For a unary struct (a tuple struct with a single field),
241the macro generates the `get`, `get_mut`, and `set` functions to
242provide a getter, a mutable getter, and a setter, respectively.
243
244```rust
245use getset::{Getters, MutGetters, CopyGetters, Setters};
246
247#[derive(Setters, Getters, MutGetters)]
248struct UnaryTuple(#[getset(set, get, get_mut)] i32);
249
250let mut tup = UnaryTuple(42);
251assert_eq!(tup.get(), &42);
252assert_eq!(tup.get_mut(), &mut 42);
253tup.set(43);
254assert_eq!(tup.get(), &43);
255
256#[derive(CopyGetters)]
257struct CopyUnaryTuple(#[getset(get_copy)] i32);
258
259let tup = CopyUnaryTuple(42);
260```
261*/
262
263#[macro_use]
264extern crate quote;
265
266use proc_macro::TokenStream;
267use proc_macro2::TokenStream as TokenStream2;
268use proc_macro_error2::{abort, abort_call_site, proc_macro_error};
269use syn::{parse_macro_input, spanned::Spanned, DataStruct, DeriveInput, Meta};
270
271use crate::generate::{GenMode, GenParams};
272
273mod generate;
274
275#[proc_macro_derive(Getters, attributes(get, with_prefix, getset))]
276#[proc_macro_error]
277pub fn getters(input: TokenStream) -> TokenStream {
278    let ast = parse_macro_input!(input as DeriveInput);
279    let params = GenParams {
280        mode: GenMode::Get,
281        global_attr: parse_global_attr(&ast.attrs, GenMode::Get),
282    };
283
284    produce(&ast, &params).into()
285}
286
287#[proc_macro_derive(CloneGetters, attributes(get_clone, with_prefix, getset))]
288#[proc_macro_error]
289pub fn clone_getters(input: TokenStream) -> TokenStream {
290    let ast = parse_macro_input!(input as DeriveInput);
291    let params = GenParams {
292        mode: GenMode::GetClone,
293        global_attr: parse_global_attr(&ast.attrs, GenMode::GetClone),
294    };
295
296    produce(&ast, &params).into()
297}
298
299#[proc_macro_derive(CopyGetters, attributes(get_copy, with_prefix, getset))]
300#[proc_macro_error]
301pub fn copy_getters(input: TokenStream) -> TokenStream {
302    let ast = parse_macro_input!(input as DeriveInput);
303    let params = GenParams {
304        mode: GenMode::GetCopy,
305        global_attr: parse_global_attr(&ast.attrs, GenMode::GetCopy),
306    };
307
308    produce(&ast, &params).into()
309}
310
311#[proc_macro_derive(MutGetters, attributes(get_mut, getset))]
312#[proc_macro_error]
313pub fn mut_getters(input: TokenStream) -> TokenStream {
314    let ast = parse_macro_input!(input as DeriveInput);
315    let params = GenParams {
316        mode: GenMode::GetMut,
317        global_attr: parse_global_attr(&ast.attrs, GenMode::GetMut),
318    };
319
320    produce(&ast, &params).into()
321}
322
323#[proc_macro_derive(Setters, attributes(set, getset))]
324#[proc_macro_error]
325pub fn setters(input: TokenStream) -> TokenStream {
326    let ast = parse_macro_input!(input as DeriveInput);
327    let params = GenParams {
328        mode: GenMode::Set,
329        global_attr: parse_global_attr(&ast.attrs, GenMode::Set),
330    };
331
332    produce(&ast, &params).into()
333}
334
335#[proc_macro_derive(WithSetters, attributes(set_with, getset))]
336#[proc_macro_error]
337pub fn with_setters(input: TokenStream) -> TokenStream {
338    let ast = parse_macro_input!(input as DeriveInput);
339    let params = GenParams {
340        mode: GenMode::SetWith,
341        global_attr: parse_global_attr(&ast.attrs, GenMode::SetWith),
342    };
343
344    produce(&ast, &params).into()
345}
346
347fn parse_global_attr(attrs: &[syn::Attribute], mode: GenMode) -> Option<Meta> {
348    attrs.iter().filter_map(|v| parse_attr(v, mode)).next_back()
349}
350
351fn parse_attr(attr: &syn::Attribute, mode: GenMode) -> Option<syn::Meta> {
352    use syn::{punctuated::Punctuated, Token};
353
354    if attr.path().is_ident("getset") {
355        let meta_list =
356            match attr.parse_args_with(Punctuated::<syn::Meta, Token![,]>::parse_terminated) {
357                Ok(list) => list,
358                Err(e) => abort!(attr.span(), "Failed to parse getset attribute: {}", e),
359            };
360
361        let (last, skip, mut collected) = meta_list
362            .into_iter()
363            .inspect(|meta| {
364                if !(meta.path().is_ident("get")
365                    || meta.path().is_ident("get_clone")
366                    || meta.path().is_ident("get_copy")
367                    || meta.path().is_ident("get_mut")
368                    || meta.path().is_ident("set")
369                    || meta.path().is_ident("set_with")
370                    || meta.path().is_ident("skip"))
371                {
372                    abort!(meta.path().span(), "unknown setter or getter")
373                }
374            })
375            .fold(
376                (None, None, Vec::new()),
377                |(last, skip, mut collected), meta| {
378                    if meta.path().is_ident(mode.name()) {
379                        (Some(meta), skip, collected)
380                    } else if meta.path().is_ident("skip") {
381                        (last, Some(meta), collected)
382                    } else {
383                        collected.push(meta);
384                        (last, skip, collected)
385                    }
386                },
387            );
388
389        if skip.is_some() {
390            // Check if there is any setter or getter used with skip, which is
391            // forbidden.
392            if last.is_none() && collected.is_empty() {
393                skip
394            } else {
395                abort!(
396                    last.or_else(|| collected.pop()).unwrap().path().span(),
397                    "use of setters and getters with skip is invalid"
398                );
399            }
400        } else {
401            last
402        }
403    } else if attr.path().is_ident(mode.name()) {
404        // If skip is not used, return the last occurrence of matching
405        // setter/getter, if there is any.
406        attr.meta.clone().into()
407    } else {
408        None
409    }
410}
411
412fn produce(ast: &DeriveInput, params: &GenParams) -> TokenStream2 {
413    let name = &ast.ident;
414    let generics = &ast.generics;
415    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
416
417    // Is it a struct?
418    if let syn::Data::Struct(DataStruct { ref fields, .. }) = ast.data {
419        // Handle unary struct
420        if matches!(fields, syn::Fields::Unnamed(_)) {
421            if fields.len() != 1 {
422                abort_call_site!("Only support unary struct!");
423            }
424            // This unwrap is safe because we know there is exactly one field
425            let field = fields.iter().next().unwrap();
426            let generated = generate::implement_for_unnamed(field, params);
427
428            quote! {
429                impl #impl_generics #name #ty_generics #where_clause {
430                    #generated
431                }
432            }
433        } else {
434            let generated = fields.iter().map(|f| generate::implement(f, params));
435
436            quote! {
437                impl #impl_generics #name #ty_generics #where_clause {
438                    #(#generated)*
439                }
440            }
441        }
442    } else {
443        // Nope. This is an Enum. We cannot handle these!
444        abort_call_site!("#[derive(Getters)] is only defined for structs, not for enums!");
445    }
446}