Derive Macro boulder::Generatable

source · []
#[derive(Generatable)]
{
    // Attributes available to this derive:
    #[boulder]
}
Expand description

Derive the Generatable trait for a type, creating a suitable Generator.

This is only implemented for structs with named fields; there is no implementation for either enums or structs with unnamed fields. All fields will be default constructed (i.e. Default::default()) in the absence of other instructions. You can customise the construction process for your type by using the boulder attribute as follows:

  • #[boulder(generator=Inc(0))] Each successive instance produced by this generator should, by default, have a value one higher for this field than the previous one. The first generated value for this field should be 0. Inc(0) can be replaced by an arbitrary expression which evaluates to a Generator.

  • #[boulder(generatable)] The type for this field implements Generatable, so new instances of the containing type should have values for this field taken from the default sequence for the field type.

  • #[boulder(generatable(a=Inc(3i32)))] The type for this field implements Generatable, and the generator for values for this field should be customised, such that the nested field a uses the generator Inc(3i32). Inc(3i32) can be replaced by an arbitrary expression which evaluates to a Generator instance.

  • #[boulder(sequence_generator=Repeat(2usize, 3usize))] This field is assumed to be a collection type (a type which can be the target of collect()). Successive instances should have alternately 2 and 3 items. The items will be default initialized. This tag stacks with generatable, buildable and default to provide more control of the container contents. Repeat(2usize, 3usize) can be replaced by an arbitrary expression which evaluates to a Generator.

The generator will additionally use all tags defined for Buildable if those specific to Generatable are not present. In this case, all instances in the sequence the generator produces will receive the same value for the given field. This includes the sequence tag.

Example:

use boulder::{Generatable, Generator, Inc};

#[derive(Generatable)]
struct Foo {
  // This field will be default initialized in every instance (a=0)
  a: i32,
  // This field will increase by 1 from 5 in successive instances.
  #[boulder(generator=Inc(5))]
  b: i32,
}

#[derive(Generatable)]
struct Bar {
  // This field will take values from Foo::generator()
  #[boulder(generatable)]
  f1: Foo,
  // This field will take values from Foo::generator().a(Inc(1)).build()
  #[boulder(generatable(a=Inc(1)))]
  f2: Foo,
  // This field will be initialized with an increasing number of
  // instances from Foo::generator().generate()
  #[boulder(generatable, sequence_generator=Inc(0usize))]
  f3: Vec<Foo>,
  // This field will be initialized with one zero in every instance
  #[boulder(sequence=1)]
  ary: Vec<i32>,
}

let mut gen = Bar::generator();
let bar = gen.generate();
assert_eq!(bar.f1.a, 0);
assert_eq!(bar.f1.b, 5);
assert_eq!(bar.f2.a, 1);
assert_eq!(bar.f2.b, 5);
assert_eq!(bar.f3.len(), 0);
assert_eq!(bar.ary.len(), 1);
assert_eq!(bar.ary[0], 0);
let bar = gen.generate();
assert_eq!(bar.f1.a, 0);
assert_eq!(bar.f1.b, 6);
assert_eq!(bar.f2.a, 2);
assert_eq!(bar.f2.b, 6);
assert_eq!(bar.f3.len(), 1);
assert_eq!(bar.f3[0].a, 0);
assert_eq!(bar.f3[0].b, 5);
assert_eq!(bar.ary.len(), 1);
assert_eq!(bar.ary[0], 0);