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, ¶ms).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, ¶ms).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, ¶ms).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, ¶ms).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, ¶ms).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, ¶ms).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}