1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
//!
//! This crate provides `Arraygen` derive macro for structs, which generates methods returning arrays filled with the selected struct fields.
//!
//! Complete example:
//!
//! ```rust
//! use arraygen::Arraygen;
//!
//! #[derive(Arraygen, Debug)]
//! #[gen_array(fn get_names: &mut String)]
//! struct Person {
//!     #[in_array(get_names)]
//!     first_name: String,
//!     #[in_array(get_names)]
//!     last_name: String,
//! }
//!
//! let mut person = Person {
//!     first_name: "Ada".into(),
//!     last_name: "Lovelace".into()
//! };
//!
//! for name in person.get_names().iter_mut() {
//!     **name = name.to_lowercase();
//! }
//!
//! assert_eq!(
//!     format!("{:?}", person),
//!     "Person { first_name: \"ada\", last_name: \"lovelace\" }"
//! );
//! ```
//!
//! As you can see above, the attribute `gen_array` generates a new method returning an array of the given type.
//! And the attribute `in_array` indicates the fields to be included by that method. In this case, the
//! generated method 'get_names' will return an array including references to all the fields of the struct.
//!
//! As you might have guessed, what `Arraygen` does under the hood is simply generating the following impl:
//!
//! ```rust
//! struct Person {
//!     first_name: String,
//!     last_name: String,
//! }
//!
//! impl Person {
//!     #[inline(always)]
//!     fn get_names(&mut self) -> [&mut String; 2] {
//!         [&mut self.first_name, &mut self.last_name]
//!     }
//! }
//! ```

extern crate arraygen;

/// 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:
///
/// ```rust
/// 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.
///
/// ```rust
/// 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.
///

pub use arraygen::Arraygen;