Crate getters2

source ·
Expand description

Derive Macro for automatically implementing getter and setter patterns for structs and enums.

§Examples

getters2 supports both structs and enums, unlike other crates that claim to implement this pattern!

§Structs

getters2 supports structs with named fields, newtype structs, and tuple structs.

§Named Fields

#[derive(Getters)]
struct Vector3 {
   x: f32,
   y: f32,
   z: f32,
}

let mut v = Vector3 { x: 1.0, y: 2.0, z: 3.0 };
assert_eq!(v.x_ref(), &1.0);
assert_eq!(v.y_ref(), &2.0);
assert_eq!(v.z_ref(), &3.0);

§Tuple Structs

Tuple structs are automatically named from first to last (there is technically a limit of 20 elements, but if you hit it, you may just want to refactor).

#[derive(Getters)]
struct Vector3(f32, f32, f32);

let mut v = Vector3(1.0, 2.0, 3.0);
assert_eq!(v.first_ref(), &1.0);
assert_eq!(v.second_ref(), &2.0);
assert_eq!(v.last_ref(), &3.0);

§Newtype Structs

Newtype structs work like a single-element tuple struct.

#[derive(Getters)]
struct Vector1(f32);

let mut v = Vector1(1.0);
assert_eq!(v.first_ref(), &1.0);

§Mutable, Clone, and Deref Getters

We don’t always want to return an immutable reference to a field. Sometimes we want to return a mutable reference, dereference the field, or clone the field. getters2 supports all of these patterns at either a struct level or a field level. Note that the field-level attributes will override the struct-level attributes, and will only work on named structs (there is no way to specify attributes on tuple or newtype struct elements).

§Mutable, Clone, and Deref Struct Getters

#[derive(Getters)]
#[getters(deref, clone, mutable)]
struct Vector3 {
  x: f32,
  y: f32,
  z: f32,
}

let mut v = Vector3 { x: 1.0, y: 2.0, z: 3.0 };
assert_eq!(v.x_ref(), &1.0);
assert_eq!(v.y_ref(), &2.0);
assert_eq!(v.z_ref(), &3.0);
assert_eq!(v.x_deref(), 1.0);
assert_eq!(v.y_deref(), 2.0);
assert_eq!(v.z_deref(), 3.0);
assert_eq!(v.x_clone(), 1.0);
assert_eq!(v.y_clone(), 2.0);
assert_eq!(v.z_clone(), 3.0);
*v.x_mut() = 4.0;
*v.y_mut() = 5.0;
*v.z_mut() = 6.0;
assert_eq!(v.x_ref(), &4.0);
assert_eq!(v.y_ref(), &5.0);
assert_eq!(v.z_ref(), &6.0);

§Mutable, Clone, and Deref Field Getters

#[derive(Getters)]
struct Vector3 {
  #[getters(deref)]
  x: f32,
  #[getters(deref)]
  y: f32,
  z: f32,
}

let mut v = Vector3 { x: 1.0, y: 2.0, z: 3.0 };
assert_eq!(v.x_ref(), &1.0);
assert_eq!(v.y_ref(), &2.0);
assert_eq!(v.z_ref(), &3.0);
assert_eq!(v.x_deref(), 1.0);
assert_eq!(v.y_deref(), 2.0);
// No z_deref method!
// assert_eq!(v.z_deref(), 3.0);

§Skipping all Getters for a Field

Sometimes we want to skip generating all getters for certain fields. We can do this by adding the skip attributes for all the getters we have enabled for the struct:

  • skip - Skips the immutable reference getter
  • skip_mutable - Skips the mutable reference getter
  • skip_deref - Skips the dereference getter
  • skip_clone - Skips the clone getter
#[derive(Getters)]
#[getters(deref, clone, mutable)]
struct Vector3 {
  #[getters(skip, skip_mutable, skip_deref, skip_clone)]
  x: f32,
  y: f32,
  z: f32,
}

let mut v = Vector3 { x: 1.0, y: 2.0, z: 3.0 };
// No x_ref method!
// assert_eq!(v.x_ref(), &1.0);
assert_eq!(v.y_ref(), &2.0);
assert_eq!(v.z_ref(), &3.0);
// No x_deref method!
// assert_eq!(v.x_deref(), 1.0);
assert_eq!(v.y_deref(), 2.0);
assert_eq!(v.z_deref(), 3.0);
// No x_clone method!
// assert_eq!(v.x_clone(), 1.0);
assert_eq!(v.y_clone(), 2.0);
assert_eq!(v.z_clone(), 3.0);
// No x_mut method!
// *v.x_mut() = 4.0;
*v.y_mut() = 4.0;
*v.z_mut() = 5.0;
// No x_ref method!
// assert_eq!(v.x_ref(), &4.0);
assert_eq!(v.y_ref(), &4.0);
assert_eq!(v.z_ref(), &5.0);

§Enums

Of course, everything we just saw for structs also works for enums. Because we don’t know which variant of an enum we have, we have to return an Option for each getter.

§Named Enums

#[derive(Getters)]
#[getters(deref, clone, mutable)]
enum Animal {
  Dog {
    #[getters(skip_deref)]
    name: String,
    age: u8
  },
  Cat {
    #[getters(skip_deref)]
    name: String,
    age: u8
  },
}
let mut dog = Animal::Dog { name: "Rover".to_string(), age: 5 };
let mut cat = Animal::Cat { name: "Mittens".to_string(), age: 3 };
assert_eq!(dog.dog_name_ref(), Some(&"Rover".to_string()));
assert_eq!(dog.dog_name_clone(), Some("Rover".to_string()));
assert_eq!(dog.dog_age_ref(), Some(&5));
assert_eq!(dog.dog_age_clone(), Some(5));

let Some(dog_name) = dog.dog_name_mut() else {
   panic!("Expected Some");
};
*dog_name = "Spot".to_string();

assert_eq!(dog.dog_name_ref(), Some(&"Spot".to_string()));

assert_eq!(cat.cat_name_ref(), Some(&"Mittens".to_string()));
assert_eq!(cat.cat_name_clone(), Some("Mittens".to_string()));
assert_eq!(cat.cat_age_ref(), Some(&3));
assert_eq!(cat.cat_age_deref(), Some(3));
assert_eq!(cat.cat_age_clone(), Some(3));

let Some(cat_name) = cat.cat_name_mut() else {
  panic!("Expected Some");
};
*cat_name = "Whiskers".to_string();

assert_eq!(cat.cat_name_ref(), Some(&"Whiskers".to_string()));

§Tuple and Newtype Enums

Tuple and newtype enums work just like tuple and newtype structs. Note that we can’t skip individual fields in tuple and newtype enums, but we can skip entire variants. Unofrtunately, this isn’t a crate limitation, just a Rust syntax limitation.Here, we just turn of deref, because we can’t dereference strings.

#[derive(Getters)]
#[getters(clone, mutable)]
enum Animal {
  Dog(String, u8),
  Cat(String, u8),
}
let mut dog = Animal::Dog("Rover".to_string(), 5);
let mut cat = Animal::Cat("Mittens".to_string(), 3);
assert_eq!(dog.dog_first_ref(), Some(&"Rover".to_string()));
assert_eq!(dog.dog_first_clone(), Some("Rover".to_string()));
assert_eq!(dog.dog_last_ref(), Some(&5));
assert_eq!(dog.dog_last_clone(), Some(5));
assert_eq!(cat.cat_first_ref(), Some(&"Mittens".to_string()));
assert_eq!(cat.cat_first_clone(), Some("Mittens".to_string()));
assert_eq!(cat.cat_last_ref(), Some(&3));
assert_eq!(cat.cat_last_clone(), Some(3));

§Skipping Enum Variants

In addition to skipping a field in a named enum variant, we can skip entire variants.

#[derive(Getters)]
#[getters(deref, clone, mutable)]
enum Animal {
  #[getters(skip, skip_mutable, skip_deref, skip_clone)]
  Dog {
    name: String,
    age: u8
  },
  #[getters(skip, skip_mutable, skip_deref, skip_clone)]
  Cat(i64),
  #[getters(skip, skip_mutable, skip_deref, skip_clone)]
  Person(String, i64, i64),
   
}

Derive Macros§

  • Derive macro for automatically implementing getter and setter patterns