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, WithSetters};
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, WithSetters};
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, WithSetters};
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, WithSetters};
150
151#[derive(CopyGetters, Setters, WithSetters)]
152#[getset(get_copy, set, set_with)]
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    fn with_skipped(mut self, val: &str) -> Self {
176        self.skipped = val.to_string();
177        self
178    }
179}
180```
181
182For a unary struct (a tuple struct with a single field),
183the macro generates the `get`, `get_mut`, and `set` functions to
184provide a getter, a mutable getter, and a setter, respectively.
185
186```rust
187use getset::{Getters, MutGetters, CopyGetters, Setters};
188
189#[derive(Setters, Getters, MutGetters)]
190struct UnaryTuple(#[getset(set, get, get_mut)] i32);
191
192let mut tup = UnaryTuple(42);
193assert_eq!(tup.get(), &42);
194assert_eq!(tup.get_mut(), &mut 42);
195tup.set(43);
196assert_eq!(tup.get(), &43);
197
198#[derive(CopyGetters)]
199struct CopyUnaryTuple(#[getset(get_copy)] i32);
200
201let tup = CopyUnaryTuple(42);
202```
203*/
204
205#[macro_use]
206extern crate quote;
207
208use proc_macro::TokenStream;
209use proc_macro2::TokenStream as TokenStream2;
210use proc_macro_error2::{abort, abort_call_site, proc_macro_error};
211use syn::{parse_macro_input, spanned::Spanned, DataStruct, DeriveInput, Meta};
212
213use crate::generate::{GenMode, GenParams};
214
215mod generate;
216
217#[proc_macro_derive(Getters, attributes(get, with_prefix, getset))]
218#[proc_macro_error]
219pub fn getters(input: TokenStream) -> TokenStream {
220    let ast = parse_macro_input!(input as DeriveInput);
221    let params = GenParams {
222        mode: GenMode::Get,
223        global_attr: parse_global_attr(&ast.attrs, GenMode::Get),
224    };
225
226    produce(&ast, &params).into()
227}
228
229#[proc_macro_derive(CopyGetters, attributes(get_copy, with_prefix, getset))]
230#[proc_macro_error]
231pub fn copy_getters(input: TokenStream) -> TokenStream {
232    let ast = parse_macro_input!(input as DeriveInput);
233    let params = GenParams {
234        mode: GenMode::GetCopy,
235        global_attr: parse_global_attr(&ast.attrs, GenMode::GetCopy),
236    };
237
238    produce(&ast, &params).into()
239}
240
241#[proc_macro_derive(MutGetters, attributes(get_mut, getset))]
242#[proc_macro_error]
243pub fn mut_getters(input: TokenStream) -> TokenStream {
244    let ast = parse_macro_input!(input as DeriveInput);
245    let params = GenParams {
246        mode: GenMode::GetMut,
247        global_attr: parse_global_attr(&ast.attrs, GenMode::GetMut),
248    };
249
250    produce(&ast, &params).into()
251}
252
253#[proc_macro_derive(Setters, attributes(set, getset))]
254#[proc_macro_error]
255pub fn setters(input: TokenStream) -> TokenStream {
256    let ast = parse_macro_input!(input as DeriveInput);
257    let params = GenParams {
258        mode: GenMode::Set,
259        global_attr: parse_global_attr(&ast.attrs, GenMode::Set),
260    };
261
262    produce(&ast, &params).into()
263}
264
265#[proc_macro_derive(WithSetters, attributes(set_with, getset))]
266#[proc_macro_error]
267pub fn with_setters(input: TokenStream) -> TokenStream {
268    let ast = parse_macro_input!(input as DeriveInput);
269    let params = GenParams {
270        mode: GenMode::SetWith,
271        global_attr: parse_global_attr(&ast.attrs, GenMode::SetWith),
272    };
273
274    produce(&ast, &params).into()
275}
276
277fn parse_global_attr(attrs: &[syn::Attribute], mode: GenMode) -> Option<Meta> {
278    attrs.iter().filter_map(|v| parse_attr(v, mode)).last()
279}
280
281fn parse_attr(attr: &syn::Attribute, mode: GenMode) -> Option<syn::Meta> {
282    use syn::{punctuated::Punctuated, Token};
283
284    if attr.path().is_ident("getset") {
285        let meta_list =
286            match attr.parse_args_with(Punctuated::<syn::Meta, Token![,]>::parse_terminated) {
287                Ok(list) => list,
288                Err(e) => abort!(attr.span(), "Failed to parse getset attribute: {}", e),
289            };
290
291        let (last, skip, mut collected) = meta_list
292            .into_iter()
293            .inspect(|meta| {
294                if !(meta.path().is_ident("get")
295                    || meta.path().is_ident("get_copy")
296                    || meta.path().is_ident("get_mut")
297                    || meta.path().is_ident("set")
298                    || meta.path().is_ident("set_with")
299                    || meta.path().is_ident("skip"))
300                {
301                    abort!(meta.path().span(), "unknown setter or getter")
302                }
303            })
304            .fold(
305                (None, None, Vec::new()),
306                |(last, skip, mut collected), meta| {
307                    if meta.path().is_ident(mode.name()) {
308                        (Some(meta), skip, collected)
309                    } else if meta.path().is_ident("skip") {
310                        (last, Some(meta), collected)
311                    } else {
312                        collected.push(meta);
313                        (last, skip, collected)
314                    }
315                },
316            );
317
318        if skip.is_some() {
319            // Check if there is any setter or getter used with skip, which is
320            // forbidden.
321            if last.is_none() && collected.is_empty() {
322                skip
323            } else {
324                abort!(
325                    last.or_else(|| collected.pop()).unwrap().path().span(),
326                    "use of setters and getters with skip is invalid"
327                );
328            }
329        } else {
330            last
331        }
332    } else if attr.path().is_ident(mode.name()) {
333        // If skip is not used, return the last occurrence of matching
334        // setter/getter, if there is any.
335        attr.meta.clone().into()
336    } else {
337        None
338    }
339}
340
341fn produce(ast: &DeriveInput, params: &GenParams) -> TokenStream2 {
342    let name = &ast.ident;
343    let generics = &ast.generics;
344    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
345
346    // Is it a struct?
347    if let syn::Data::Struct(DataStruct { ref fields, .. }) = ast.data {
348        // Handle unary struct
349        if matches!(fields, syn::Fields::Unnamed(_)) {
350            if fields.len() != 1 {
351                abort_call_site!("Only support unary struct!");
352            }
353            // This unwrap is safe because we know there is exactly one field
354            let field = fields.iter().next().unwrap();
355            let generated = generate::implement_for_unnamed(field, params);
356
357            quote! {
358                impl #impl_generics #name #ty_generics #where_clause {
359                    #generated
360                }
361            }
362        } else {
363            let generated = fields.iter().map(|f| generate::implement(f, params));
364
365            quote! {
366                impl #impl_generics #name #ty_generics #where_clause {
367                    #(#generated)*
368                }
369            }
370        }
371    } else {
372        // Nope. This is an Enum. We cannot handle these!
373        abort_call_site!("#[derive(Getters)] is only defined for structs, not for enums!");
374    }
375}