[−][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 bygen_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.