getters3/lib.rs
1// Copyright (C) 2023-2024 Rowan Hart
2// SPDX-License-Identifier: Apache-2.0
3
4//! Derive Macro for automatically implementing getter and setter patterns
5//! for structs and enums.
6//!
7//! # Examples
8//!
9//! `getters2` supports both structs and enums, unlike other crates that claim to implement this
10//! pattern!
11//!
12//! ## Structs
13//!
14//! `getters2` supports structs with named fields, newtype structs, and tuple structs.
15//!
16//! ### Named Fields
17//!
18//! ```rust
19//! # use getters2::Getters;
20//! #[derive(Getters)]
21//! struct Vector3 {
22//! x: f32,
23//! y: f32,
24//! z: f32,
25//! }
26//!
27//! let mut v = Vector3 { x: 1.0, y: 2.0, z: 3.0 };
28//! assert_eq!(v.x_ref(), &1.0);
29//! assert_eq!(v.y_ref(), &2.0);
30//! assert_eq!(v.z_ref(), &3.0);
31//! ```
32//!
33//! ### Tuple Structs
34//!
35//! Tuple structs are automatically named from first to last (there is technically a
36//! limit of 20 elements, but if you hit it, you may just want to refactor).
37//!
38//! ```rust
39//! # use getters2::Getters;
40//! #[derive(Getters)]
41//! struct Vector3(f32, f32, f32);
42//!
43//! let mut v = Vector3(1.0, 2.0, 3.0);
44//! assert_eq!(v.first_ref(), &1.0);
45//! assert_eq!(v.second_ref(), &2.0);
46//! assert_eq!(v.last_ref(), &3.0);
47//! ```
48//!
49//! ### Newtype Structs
50//!
51//! Newtype structs work like a single-element tuple struct.
52//!
53//! ```rust
54//! # use getters2::Getters;
55//! #[derive(Getters)]
56//! struct Vector1(f32);
57//!
58//! let mut v = Vector1(1.0);
59//! assert_eq!(v.first_ref(), &1.0);
60//! ```
61//!
62//! ### Mutable, Clone, and Deref Getters
63//!
64//! We don't always want to return an immutable reference to a field. Sometimes we want
65//! to return a mutable reference, dereference the field, or clone the field. `getters2`
66//! supports all of these patterns at either a struct level or a field level. Note that
67//! the field-level attributes will override the struct-level attributes, and will only
68//! work on named structs (there is no way to specify attributes on tuple or newtype
69//! struct elements).
70//!
71//! ### Mutable, Clone, and Deref Struct Getters
72//!
73//! ```rust
74//! # use getters2::Getters;
75//! #[derive(Getters)]
76//! #[getters(deref, clone, mutable)]
77//! struct Vector3 {
78//! x: f32,
79//! y: f32,
80//! z: f32,
81//! }
82//!
83//! let mut v = Vector3 { x: 1.0, y: 2.0, z: 3.0 };
84//! assert_eq!(v.x_ref(), &1.0);
85//! assert_eq!(v.y_ref(), &2.0);
86//! assert_eq!(v.z_ref(), &3.0);
87//! assert_eq!(v.x_deref(), 1.0);
88//! assert_eq!(v.y_deref(), 2.0);
89//! assert_eq!(v.z_deref(), 3.0);
90//! assert_eq!(v.x_clone(), 1.0);
91//! assert_eq!(v.y_clone(), 2.0);
92//! assert_eq!(v.z_clone(), 3.0);
93//! *v.x_mut() = 4.0;
94//! *v.y_mut() = 5.0;
95//! *v.z_mut() = 6.0;
96//! assert_eq!(v.x_ref(), &4.0);
97//! assert_eq!(v.y_ref(), &5.0);
98//! assert_eq!(v.z_ref(), &6.0);
99//! ```
100//!
101//! ### Mutable, Clone, and Deref Field Getters
102//!
103//! ```rust
104//! # use getters2::Getters;
105//! #[derive(Getters)]
106//! struct Vector3 {
107//! #[getters(deref)]
108//! x: f32,
109//! #[getters(deref)]
110//! y: f32,
111//! z: f32,
112//! }
113//!
114//! let mut v = Vector3 { x: 1.0, y: 2.0, z: 3.0 };
115//! assert_eq!(v.x_ref(), &1.0);
116//! assert_eq!(v.y_ref(), &2.0);
117//! assert_eq!(v.z_ref(), &3.0);
118//! assert_eq!(v.x_deref(), 1.0);
119//! assert_eq!(v.y_deref(), 2.0);
120//! // No z_deref method!
121//! // assert_eq!(v.z_deref(), 3.0);
122//! ```
123//!
124//! ### Skipping all Getters for a Field
125//!
126//! Sometimes we want to skip generating all getters for certain fields. We can do this
127//! by adding the skip attributes for all the getters we have enabled for the struct:
128//!
129//! * `skip` - Skips the immutable reference getter
130//! * `skip_mutable` - Skips the mutable reference getter
131//! * `skip_deref` - Skips the dereference getter
132//! * `skip_clone` - Skips the clone getter
133//!
134//! ```rust
135//! # use getters2::Getters;
136//! #[derive(Getters)]
137//! #[getters(deref, clone, mutable)]
138//! struct Vector3 {
139//! #[getters(skip, skip_mutable, skip_deref, skip_clone)]
140//! x: f32,
141//! y: f32,
142//! z: f32,
143//! }
144//!
145//! let mut v = Vector3 { x: 1.0, y: 2.0, z: 3.0 };
146//! // No x_ref method!
147//! // assert_eq!(v.x_ref(), &1.0);
148//! assert_eq!(v.y_ref(), &2.0);
149//! assert_eq!(v.z_ref(), &3.0);
150//! // No x_deref method!
151//! // assert_eq!(v.x_deref(), 1.0);
152//! assert_eq!(v.y_deref(), 2.0);
153//! assert_eq!(v.z_deref(), 3.0);
154//! // No x_clone method!
155//! // assert_eq!(v.x_clone(), 1.0);
156//! assert_eq!(v.y_clone(), 2.0);
157//! assert_eq!(v.z_clone(), 3.0);
158//! // No x_mut method!
159//! // *v.x_mut() = 4.0;
160//! *v.y_mut() = 4.0;
161//! *v.z_mut() = 5.0;
162//! // No x_ref method!
163//! // assert_eq!(v.x_ref(), &4.0);
164//! assert_eq!(v.y_ref(), &4.0);
165//! assert_eq!(v.z_ref(), &5.0);
166//! ```
167//!
168//! ## Enums
169//!
170//! Of course, everything we just saw for structs also works for enums. Because we don't know
171//! which variant of an enum we have, we have to return an `Option` for each getter.
172//!
173//! ### Named Enums
174//!
175//! ```rust
176//! # use getters2::Getters;
177//! #[derive(Getters)]
178//! #[getters(deref, clone, mutable)]
179//! enum Animal {
180//! Dog {
181//! #[getters(skip_deref)]
182//! name: String,
183//! age: u8
184//! },
185//! Cat {
186//! #[getters(skip_deref)]
187//! name: String,
188//! age: u8
189//! },
190//! }
191//! let mut dog = Animal::Dog { name: "Rover".to_string(), age: 5 };
192//! let mut cat = Animal::Cat { name: "Mittens".to_string(), age: 3 };
193//! assert_eq!(dog.dog_name_ref(), Some(&"Rover".to_string()));
194//! assert_eq!(dog.dog_name_clone(), Some("Rover".to_string()));
195//! assert_eq!(dog.dog_age_ref(), Some(&5));
196//! assert_eq!(dog.dog_age_clone(), Some(5));
197//!
198//! let Some(dog_name) = dog.dog_name_mut() else {
199//! panic!("Expected Some");
200//! };
201//! *dog_name = "Spot".to_string();
202//!
203//! assert_eq!(dog.dog_name_ref(), Some(&"Spot".to_string()));
204//!
205//! assert_eq!(cat.cat_name_ref(), Some(&"Mittens".to_string()));
206//! assert_eq!(cat.cat_name_clone(), Some("Mittens".to_string()));
207//! assert_eq!(cat.cat_age_ref(), Some(&3));
208//! assert_eq!(cat.cat_age_deref(), Some(3));
209//! assert_eq!(cat.cat_age_clone(), Some(3));
210//!
211//! let Some(cat_name) = cat.cat_name_mut() else {
212//! panic!("Expected Some");
213//! };
214//! *cat_name = "Whiskers".to_string();
215//!
216//! assert_eq!(cat.cat_name_ref(), Some(&"Whiskers".to_string()));
217//! ```
218//!
219//! ## Tuple and Newtype Enums
220//!
221//! Tuple and newtype enums work just like tuple and newtype structs. Note that we can't
222//! skip individual fields in tuple and newtype enums, but we can skip entire variants.
223//! Unofrtunately, this isn't a crate limitation, just a Rust syntax limitation.Here, we
224//! just turn of deref, because we can't dereference strings.
225//!
226//! ```rust
227//! # use getters2::Getters;
228//! #[derive(Getters)]
229//! #[getters(clone, mutable)]
230//! enum Animal {
231//! Dog(String, u8),
232//! Cat(String, u8),
233//! }
234//! let mut dog = Animal::Dog("Rover".to_string(), 5);
235//! let mut cat = Animal::Cat("Mittens".to_string(), 3);
236//! assert_eq!(dog.dog_first_ref(), Some(&"Rover".to_string()));
237//! assert_eq!(dog.dog_first_clone(), Some("Rover".to_string()));
238//! assert_eq!(dog.dog_last_ref(), Some(&5));
239//! assert_eq!(dog.dog_last_clone(), Some(5));
240//! assert_eq!(cat.cat_first_ref(), Some(&"Mittens".to_string()));
241//! assert_eq!(cat.cat_first_clone(), Some("Mittens".to_string()));
242//! assert_eq!(cat.cat_last_ref(), Some(&3));
243//! assert_eq!(cat.cat_last_clone(), Some(3));
244//! ```
245//!
246//! ### Skipping Enum Variants
247//!
248//! In addition to skipping a field in a named enum variant, we can skip entire variants.
249//!
250//! ```rust
251//! # use getters2::Getters;
252//! #[derive(Getters)]
253//! #[getters(deref, clone, mutable)]
254//! enum Animal {
255//! #[getters(skip, skip_mutable, skip_deref, skip_clone)]
256//! Dog {
257//! name: String,
258//! age: u8
259//! },
260//! #[getters(skip, skip_mutable, skip_deref, skip_clone)]
261//! Cat(i64),
262//! #[getters(skip, skip_mutable, skip_deref, skip_clone)]
263//! Person(String, i64, i64),
264//!
265//! }
266//! ```
267
268#![allow(unused_variables)]
269#![deny(missing_docs)]
270
271use darling::{
272 ast::{Data, Fields},
273 util::Flag,
274 FromDeriveInput, FromField, FromVariant,
275};
276use proc_macro::TokenStream;
277use proc_macro2::{Span, TokenStream as TokenStream2};
278use proc_macro_error2::abort;
279use quote::{format_ident, quote, ToTokens};
280use syn::{
281 parse_macro_input, Attribute, DeriveInput, Expr, Generics, Ident, Index, Member, Type,
282 Visibility,
283};
284
285#[derive(Debug, FromField)]
286#[darling(attributes(getters))]
287struct GettersField {
288 ident: Option<Ident>,
289 #[allow(unused)]
290 vis: Visibility,
291 ty: Type,
292 #[allow(unused)]
293 attrs: Vec<Attribute>,
294 mutable: Flag,
295 deref: Flag,
296 clone: Flag,
297 skip: Flag,
298 skip_mutable: Flag,
299 skip_deref: Flag,
300 skip_clone: Flag,
301}
302
303#[derive(Debug, FromVariant)]
304#[darling(attributes(getters))]
305struct GettersVariant {
306 ident: Ident,
307 discriminant: Option<Expr>,
308 fields: Fields<GettersField>,
309 #[allow(unused)]
310 attrs: Vec<Attribute>,
311 #[allow(unused)]
312 mutable: Flag,
313 #[allow(unused)]
314 deref: Flag,
315 #[allow(unused)]
316 clone: Flag,
317 skip: Flag,
318 skip_mutable: Flag,
319 skip_deref: Flag,
320 skip_clone: Flag,
321}
322
323#[derive(Debug, FromDeriveInput)]
324#[darling(
325 attributes(getters),
326 supports(
327 struct_named,
328 struct_newtype,
329 struct_tuple,
330 enum_named,
331 enum_newtype,
332 enum_tuple,
333 enum_unit
334 ),
335 // NOTE: https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index
336 forward_attrs(
337 cfg,
338 derive,
339 allow,
340 warn,
341 deny,
342 forbid,
343 deprecated,
344 must_use,
345 doc,
346 non_exhaustive
347 )
348)]
349struct GettersInput {
350 ident: Ident,
351 #[allow(unused)]
352 vis: Visibility,
353 generics: Generics,
354 data: Data<GettersVariant, GettersField>,
355 #[allow(unused)]
356 attrs: Vec<Attribute>,
357 mutable: Flag,
358 clone: Flag,
359 deref: Flag,
360}
361
362impl GettersInput {
363 fn method_field(&self, field: &GettersField, index: usize, max: usize) -> TokenStream2 {
364 let ty = &field.ty;
365 let immutable = !field.skip.is_present();
366 let mutable = (field.mutable.is_present() || self.mutable.is_present())
367 && !field.skip_mutable.is_present();
368 let clone =
369 (field.clone.is_present() || self.clone.is_present()) && !field.skip_clone.is_present();
370 let deref =
371 (field.deref.is_present() || self.deref.is_present()) && !field.skip_deref.is_present();
372
373 let (immutable, maybe_mutable, maybe_clone, maybe_deref) =
374 if let Some(ident) = field.ident.as_ref() {
375 let ident_ref = format_ident!("{}_ref", ident);
376 let ident_mut = format_ident!("{}_mut", ident);
377 let ident_clone = format_ident!("{}_clone", ident);
378 let ident_deref = format_ident!("{}_deref", ident);
379 (
380 immutable
381 .then_some(quote! {
382 #[inline(always)]
383 /// Return an immutable reference to the field
384 pub fn #ident_ref(&self) -> &#ty {
385 &self.#ident
386 }
387 })
388 .unwrap_or_default(),
389 mutable
390 .then_some(quote! {
391 #[inline(always)]
392 /// Return a mutable reference to the field
393 pub fn #ident_mut(&mut self) -> &mut #ty {
394 &mut self.#ident
395 }
396 })
397 .unwrap_or_default(),
398 clone
399 .then_some(quote! {
400 #[inline(always)]
401 /// Return a clone of the field
402 pub fn #ident_clone(&self) -> #ty {
403 self.#ident.clone()
404 }
405 })
406 .unwrap_or_default(),
407 deref
408 .then_some(quote! {
409 #[inline(always)]
410 /// Return a copy of the field
411 pub fn #ident_deref(&self) -> #ty {
412 self.#ident
413 }
414 })
415 .unwrap_or_default(),
416 )
417 } else {
418 // Field with no ident, we generate a named method
419 let name = method_name(index, max);
420 let name_ref = format_ident!("{}_ref", name);
421 let name_mut = format_ident!("{}_mut", name);
422 let name_clone = format_ident!("{}_clone", name);
423 let name_deref = format_ident!("{}_deref", name);
424 let index = Member::Unnamed(Index {
425 index: index as u32,
426 span: Span::call_site(),
427 });
428
429 (
430 immutable
431 .then_some(quote! {
432 #[inline(always)]
433 /// Return an immutable reference to the field
434 pub fn #name_ref(&self) -> &#ty {
435 &self.#index
436 }
437 })
438 .unwrap_or_default(),
439 mutable
440 .then_some(quote! {
441 #[inline(always)]
442 /// Return a mutable reference to the field
443 pub fn #name_mut(&mut self) -> &mut #ty {
444 &mut self.#index
445 }
446 })
447 .unwrap_or_default(),
448 clone
449 .then_some(quote! {
450 #[inline(always)]
451 /// Return a clone of the field
452 pub fn #name_clone(&self) -> #ty {
453 self.#index.clone()
454 }
455 })
456 .unwrap_or_default(),
457 deref
458 .then_some(quote! {
459 #[inline(always)]
460 /// Return a copy of the field
461 pub fn #name_deref(&self) -> #ty {
462 self.#index
463 }
464 })
465 .unwrap_or_default(),
466 )
467 };
468
469 quote! {
470 #immutable
471 #maybe_mutable
472 #maybe_clone
473 #maybe_deref
474 }
475 }
476
477 #[allow(clippy::too_many_arguments)]
478 fn method_variant(
479 &self,
480 field: &GettersField,
481 index: usize,
482 max: usize,
483 enum_ident: &Ident,
484 variant_ident: &Ident,
485 skip: bool,
486 skip_mutable: bool,
487 skip_clone: bool,
488 skip_deref: bool,
489 ) -> TokenStream2 {
490 let ty = &field.ty;
491 let immutable = !field.skip.is_present() && !skip;
492 let mutable = (field.mutable.is_present() || self.mutable.is_present())
493 && !field.skip_mutable.is_present()
494 && !skip_mutable;
495 let clone = (field.clone.is_present() || self.clone.is_present())
496 && !field.skip_clone.is_present()
497 && !skip_clone;
498 let deref = (field.deref.is_present() || self.deref.is_present())
499 && !field.skip_deref.is_present()
500 && !skip_deref;
501 let prefix = variant_ident.to_string().to_ascii_lowercase();
502
503 let (immutable, maybe_mutable, maybe_clone, maybe_deref) =
504 if let Some(ident) = field.ident.as_ref() {
505 let ident_ref = format_ident!("{}_{}_ref", prefix, ident);
506 let ident_mut = format_ident!("{}_{}_mut", prefix, ident);
507 let ident_clone = format_ident!("{}_{}_clone", prefix, ident);
508 let ident_deref = format_ident!("{}_{}_deref", prefix, ident);
509 (
510 immutable
511 .then_some(quote! {
512 #[inline(always)]
513 /// Return an immutable reference to the field
514 pub fn #ident_ref(&self) -> Option<&#ty> {
515 if let #enum_ident::#variant_ident { #ident, .. } = self {
516 Some(#ident)
517 } else {
518 None
519 }
520 }
521 })
522 .unwrap_or_default(),
523 mutable
524 .then_some(quote! {
525 #[inline(always)]
526 /// Return a mutable reference to the field
527 pub fn #ident_mut(&mut self) -> Option<&mut #ty> {
528 if let #enum_ident::#variant_ident { ref mut #ident, .. } = self {
529 Some(#ident)
530 } else {
531 None
532 }
533 }
534 })
535 .unwrap_or_default(),
536 clone
537 .then_some(quote! {
538 #[inline(always)]
539 /// Return a clone of the field
540 pub fn #ident_clone(&self) -> Option<#ty> {
541 if let #enum_ident::#variant_ident { #ident, .. } = self {
542 Some(#ident.clone())
543 } else {
544 None
545 }
546 }
547 })
548 .unwrap_or_default(),
549 deref
550 .then_some(quote! {
551 #[inline(always)]
552 /// Return a copy of the field
553 pub fn #ident_deref(&self) -> Option<#ty> {
554 if let #enum_ident::#variant_ident { #ident, .. } = self {
555 Some(*#ident)
556 } else {
557 None
558 }
559 }
560 })
561 .unwrap_or_default(),
562 )
563 } else {
564 // Field with no ident, we generate a named method
565 let name = method_name(index, max);
566 let name_ref = format_ident!("{}_{}_ref", prefix, name);
567 let name_mut = format_ident!("{}_{}_mut", prefix, name);
568 let name_clone = format_ident!("{}_{}_clone", prefix, name);
569 let name_deref = format_ident!("{}_{}_deref", prefix, name);
570 let elements = tuple_elements(index, max);
571 let elements_mut = tuple_elements_mut(index, max);
572 let element = tuple_element_name(index);
573
574 (
575 immutable
576 .then_some(quote! {
577 #[inline(always)]
578 /// Return an immutable reference to the field
579 pub fn #name_ref(&self) -> Option<&#ty> {
580 if let #enum_ident::#variant_ident(#elements) = self {
581 Some(#element)
582 } else {
583 None
584 }
585 }
586 })
587 .unwrap_or_default(),
588 mutable
589 .then_some(quote! {
590 #[inline(always)]
591 /// Retur a mutable reference to the field
592 pub fn #name_mut(&mut self) -> Option<&mut #ty> {
593 if let #enum_ident::#variant_ident(#elements_mut) = self {
594 Some(#element)
595 } else {
596 None
597 }
598 }
599 })
600 .unwrap_or_default(),
601 clone
602 .then_some(quote! {
603 #[inline(always)]
604 /// Return a clone of the field
605 pub fn #name_clone(&self) -> Option<#ty> {
606 if let #enum_ident::#variant_ident(#elements) = self {
607 Some(#element.clone())
608 } else {
609 None
610 }
611 }
612 })
613 .unwrap_or_default(),
614 deref
615 .then_some(quote! {
616 #[inline(always)]
617 /// Return a copy of the field
618 pub fn #name_deref(&self) -> Option<#ty> {
619 if let #enum_ident::#variant_ident(#elements) = self {
620 Some(*#element)
621 } else {
622 None
623 }
624 }
625 })
626 .unwrap_or_default(),
627 )
628 };
629
630 quote! {
631 #immutable
632 #maybe_mutable
633 #maybe_clone
634 #maybe_deref
635 }
636 }
637
638 fn methods_struct(&self, fields: &Fields<&GettersField>) -> TokenStream2 {
639 fields
640 .iter()
641 .enumerate()
642 .map(|(i, f)| self.method_field(f, i, fields.len()))
643 .collect::<TokenStream2>()
644 }
645
646 fn methods_enum(&self, variants: &[&GettersVariant]) -> TokenStream2 {
647 variants
648 .iter()
649 .map(|v| {
650 let variant_ident = &v.ident;
651
652 if let Some(discriminant) = v.discriminant.as_ref() {
653 abort!(
654 discriminant,
655 "Getters cannot be derived for enums with discriminants"
656 )
657 }
658
659 v.fields
660 .iter()
661 .enumerate()
662 .map(|(i, f)| {
663 self.method_variant(
664 f,
665 i,
666 v.fields.len(),
667 &self.ident,
668 variant_ident,
669 v.skip.is_present(),
670 v.skip_mutable.is_present(),
671 v.skip_clone.is_present(),
672 v.skip_deref.is_present(),
673 )
674 })
675 .collect::<TokenStream2>()
676 })
677 .collect::<TokenStream2>()
678 }
679}
680
681impl ToTokens for GettersInput {
682 fn to_tokens(&self, tokens: &mut TokenStream2) {
683 let ident = &self.ident;
684 let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();
685
686 let methods = if let Some(ref fields) = self.data.as_ref().take_struct() {
687 self.methods_struct(fields)
688 } else if let Some(ref variants) = self.data.as_ref().take_enum() {
689 self.methods_enum(variants)
690 } else {
691 abort!(
692 self.ident,
693 "Getters can only be derived for structs and enums"
694 )
695 };
696
697 tokens.extend(quote! {
698 impl #impl_generics #ident #ty_generics #where_clause {
699 #methods
700 }
701 })
702 }
703}
704
705#[proc_macro_derive(Getters, attributes(getters))]
706#[allow(non_snake_case)]
707/// Derive macro for automatically implementing getter and setter patterns
708///
709/// # Examples
710///
711/// Structs:
712///
713/// ```rust
714/// # use getters2::Getters;
715/// #[derive(Getters)]
716/// #[getters(deref, clone, mutable)]
717/// struct NamedVector3 {
718/// x: f32,
719/// y: f32,
720/// z: f32,
721/// #[getters(skip_deref)]
722/// // NOTE: Skip deref, can't dereference strings.
723/// name: String,
724/// }
725///
726/// let mut v = NamedVector3 { x: 1.0, y: 2.0, z: 3.0, name: "foo".to_string() };
727/// assert_eq!(v.x_ref(), &1.0);
728/// assert_eq!(v.y_deref(), 2.0);
729/// assert_eq!(v.z_clone(), 3.0);
730/// *v.x_mut() = 4.0;
731/// assert_eq!(v.x_ref(), &4.0);
732/// ```
733///
734/// Tuple Structs:
735///
736/// ```rust
737/// # use getters2::Getters;
738///
739/// #[derive(Getters)]
740/// #[getters(deref, clone, mutable)]
741/// struct TupleVector3(f32, f32, f32);
742///
743/// let mut v = TupleVector3(1.0, 2.0, 3.0);
744///
745/// assert_eq!(v.first_ref(), &1.0);
746/// assert_eq!(v.second_deref(), 2.0);
747/// assert_eq!(v.last_clone(), 3.0);
748/// *v.first_mut() = 4.0;
749/// assert_eq!(v.first_ref(), &4.0);
750/// ```
751///
752/// Named Enums:
753///
754/// ```rust
755/// # use getters2::Getters;
756///
757/// #[derive(Getters)]
758/// #[getters(deref, clone, mutable)]
759/// enum Animal {
760/// Dog {
761/// #[getters(skip_deref)]
762/// name: String,
763/// age: u8
764/// },
765/// Cat {
766/// #[getters(skip_deref)]
767/// name: String,
768/// age: u8
769/// },
770/// }
771///
772/// let mut dog = Animal::Dog { name: "Rover".to_string(), age: 5 };
773/// let mut cat = Animal::Cat { name: "Mittens".to_string(), age: 3 };
774///
775/// assert_eq!(dog.dog_name_ref(), Some(&"Rover".to_string()));
776/// assert_eq!(dog.dog_name_clone(), Some("Rover".to_string()));
777/// assert_eq!(dog.dog_age_ref(), Some(&5));
778/// assert_eq!(dog.dog_age_deref(), Some(5));
779/// assert_eq!(cat.cat_name_ref(), Some(&"Mittens".to_string()));
780/// assert_eq!(cat.cat_name_clone(), Some("Mittens".to_string()));
781/// assert_eq!(cat.cat_age_ref(), Some(&3));
782/// assert_eq!(cat.cat_age_deref(), Some(3));
783/// ```
784///
785/// Tuple Enums:
786///
787/// ```rust
788/// # use getters2::Getters;
789///
790/// #[derive(Getters)]
791/// #[getters(clone, mutable)]
792/// enum Animal {
793/// Dog(String, u8),
794/// Cat(String, u8),
795/// }
796///
797/// let mut dog = Animal::Dog("Rover".to_string(), 5);
798/// let mut cat = Animal::Cat("Mittens".to_string(), 3);
799///
800/// assert_eq!(dog.dog_first_ref(), Some(&"Rover".to_string()));
801/// assert_eq!(dog.dog_first_clone(), Some("Rover".to_string()));
802/// assert_eq!(dog.dog_last_ref(), Some(&5));
803/// assert_eq!(dog.dog_last_clone(), Some(5));
804/// assert_eq!(cat.cat_first_ref(), Some(&"Mittens".to_string()));
805/// assert_eq!(cat.cat_first_clone(), Some("Mittens".to_string()));
806/// assert_eq!(cat.cat_last_ref(), Some(&3));
807/// assert_eq!(cat.cat_last_clone(), Some(3));
808/// ```
809///
810pub fn Getters(input: TokenStream) -> TokenStream {
811 let getters = match GettersInput::from_derive_input(&parse_macro_input!(input as DeriveInput)) {
812 Ok(g) => g,
813 Err(e) => {
814 return TokenStream::from(e.write_errors());
815 }
816 };
817
818 let mut tokens = TokenStream2::new();
819
820 getters.to_tokens(&mut tokens);
821
822 tokens.into()
823}
824
825const NUMERAL_TO_ORDINAL: [&str; 20] = [
826 "first",
827 "second",
828 "third",
829 "fourth",
830 "fifth",
831 "sixth",
832 "seventh",
833 "eigth",
834 "ninth",
835 "tenth",
836 "eleventh",
837 "twelfth",
838 "thirteenth",
839 "fourteenth",
840 "fifteenth",
841 "sixteenth",
842 "seventeenth",
843 "eighteenth",
844 "nineteenth",
845 "twentieth",
846];
847const LAST: &str = "last";
848
849/// Given an index (0, 1, 2, ...) return the name of the method
850/// (first, second, third, ..., last)
851fn method_name(i: usize, max: usize) -> Ident {
852 if i == max - 1 && max != 1 {
853 Ident::new(LAST, Span::call_site())
854 } else {
855 Ident::new(NUMERAL_TO_ORDINAL[i], Span::call_site())
856 }
857}
858
859const TUPLE_ELEMENTS: [&str; 20] = [
860 "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
861 "t",
862];
863
864fn tuple_element_name(index: usize) -> Ident {
865 Ident::new(TUPLE_ELEMENTS[index], Span::call_site())
866}
867
868fn tuple_elements(index: usize, max: usize) -> TokenStream2 {
869 (0..max)
870 .map(tuple_element_name)
871 .enumerate()
872 .map(|(i, n)| {
873 let ident = if i == index {
874 format_ident!("{}", n)
875 } else {
876 format_ident!("_{}", n)
877 };
878
879 if i == max - 1 {
880 quote!(ref #ident)
881 } else {
882 quote!(ref #ident,)
883 }
884 })
885 .collect::<TokenStream2>()
886}
887
888fn tuple_elements_mut(index: usize, max: usize) -> TokenStream2 {
889 (0..max)
890 .map(tuple_element_name)
891 .enumerate()
892 .map(|(i, n)| {
893 let ident = if i == index {
894 format_ident!("{}", n)
895 } else {
896 format_ident!("_{}", n)
897 };
898
899 let maybe_mut = if i == index { quote!(mut) } else { quote!() };
900
901 if i == max - 1 {
902 quote!(ref #maybe_mut #ident)
903 } else {
904 quote!(ref #maybe_mut #ident,)
905 }
906 })
907 .collect::<TokenStream2>()
908}