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;