[][src]Derive Macro arraygen::Arraygen

#[derive(Arraygen)]
{
    // Attributes available to this derive:
    #[gen_array]
    #[in_array]
}

The Arraygen derive allows you to use the attribute gen_array at the struct level and the attribute in_array in each contained field.

With gen_array you can declare your Arraygen methods in the following way:

#[gen_array(?visibility fn your_method_name: YourReturnType)]

  • ?visibility is optional, you can let it blank entirely, or write pub, pub(crate) and any other pub variant.
  • your_method_name can be any valid method name. You can't use a name taken by another mehtod in the struct impl, including also other Arraygen methods. Otherwise you will get an error.
  • YourReturnType can be any Rust type that can appear in a struct field. Notice that if the type does not implement the trait 'Copy', you are better returning &type or &mut type instead, in order to avoid ownership errors.

There is no limit in the number of methods you can declare.

By default, those new Arraygen methods return arrays of length 0. That's not very useful, but that's why we also have the attribute in_array.

With in_array you indicate which field is returned by which method generated by gen_array. Sintax is the following one:

#[in_array(your_method_name)]

  • your_method_name needs to be some method name generated by gen_array.

This is the way to fill up your Arraygen methods.

The only thing you need to care about is that the type returned by your_method_name needs to be compatible with the type of the field with the in_array attribute. Notice that non-reference field types can be returned as references, but not the other way around.

Is also good to know that the same field can be included in many Arraygen methods, not just in only one. You will see what I mean by checking the following example:

use arraygen::Arraygen;

#[derive(Arraygen)]
#[gen_array(fn odds: i32)]
#[gen_array(fn evens: i32)]
#[gen_array(fn primes: i32)]
struct Numbers {
    #[in_array(odds)]
    one: i32,

    #[in_array(evens)]
    #[in_array(primes)]
    two: i32,

    #[in_array(odds, primes)] // This syntax is also valid, by the way.
    three: i32,

    #[in_array(evens)]
    four: i32,

    #[in_array(odds, primes)]
    five: i32
}

let numbers = Numbers {
    one: 1,
    two: 2,
    three: 3,
    four: 4,
    five: 5
};

assert_eq!(numbers.odds(), [1, 3, 5]);
assert_eq!(numbers.evens(), [2, 4]);
assert_eq!(numbers.primes(), [2, 3, 5]);

Trait Objects

A very good use of Arraygen is being able to extract trait objects from different concrete types, so you can operate in all of them at once.

use arraygen::Arraygen;

trait Animal {
    fn talk(&self) -> &'static str;
}

struct Dog {}
impl Animal for Dog {
    fn talk(&self) -> &'static str {
        "bark"
    }
}

struct Cat {}
impl Animal for Cat {
    fn talk(&self) -> &'static str {
        "meow"
    }
}

#[derive(Arraygen)]
#[gen_array(fn get_animals: &dyn Animal)]
struct Animals {
    #[in_array(get_animals)]
    dogo: Dog,
    #[in_array(get_animals)]
    tiger: Cat,
    #[in_array(get_animals)]
    kitty: Cat,
}

let animals = Animals {
    dogo: Dog {},
    tiger: Cat {},
    kitty: Cat {}
};

let talk: Vec<&'static str> = animals
    .get_animals()
    .iter()
    .map(|animal| animal.talk())
    .collect();

assert_eq!(talk, ["bark", "meow", "meow"]);

And a more realistic example could be this other one:

use arraygen::Arraygen;

trait SetNone {
    fn set_none(&mut self);
}

impl<T> SetNone for Option<T> {
    fn set_none(&mut self) {
        *self = None;
    }
}

#[derive(Arraygen)]
#[gen_array(fn ephemeral_options: &mut dyn SetNone)]
struct ManyOptions {
    #[in_array(ephemeral_options)]
    a: Option<i32>,
    #[in_array(ephemeral_options)]
    b: Option<String>,
    c: Option<String>,
}

let mut many = ManyOptions {
    a: Some(42),
    b: Some(String::from("foo")),
    c: Some(String::from("bar"))
};

for option in many.ephemeral_options().iter_mut() {
    option.set_none();
}

assert_eq!(many.a, None);
assert_eq!(many.b, None);
assert_eq!(many.c, Some(String::from("bar")));

With ad-hoc traits and Arraygen is very easy to generalize common transformations with simple one-liners.