|
| 1 | +//! # `#[typle(...)]` |
1 | 2 | //! The `typle` attribute macro generates code for multiple tuple lengths. This code: |
2 | 3 | //! |
3 | 4 | //! ```rust |
|
45 | 46 | //! /// Split off the first component of a tuple. |
46 | 47 | //! #[typle(Tuple for 1..=12)] |
47 | 48 | //! fn split_first<T: Tuple>( |
48 | | -//! t: T // t: (T<0>, T<1>, T<2>,...) |
49 | | -//! ) -> (T<0>, (T<{1..}>)) // (T<0>, (T<1>, T<2>,...)) |
| 49 | +//! t: T // t: (T<0>, T<1>, T<2>,...) |
| 50 | +//! ) -> (T<0>, (T<{1..}>)) // -> (T<0>, (T<1>, T<2>,...)) |
50 | 51 | //! { |
51 | | -//! (t[[0]], (t[[1..]])) // (t.0, (t.1, t.2,...)) |
| 52 | +//! (t[[0]], (t[[1..]])) // (t.0, (t.1, t.2,...)) |
52 | 53 | //! } |
53 | 54 | //! |
54 | 55 | //! assert_eq!(split_first(('1', 2, 3.0)), ('1', (2, 3.0))); |
55 | 56 | //! assert_eq!(split_first((2, 3.0)), (2, (3.0,))); |
56 | 57 | //! assert_eq!(split_first((3.0,)), (3.0, ())); |
57 | 58 | //! ``` |
58 | 59 | //! |
| 60 | +//! # `typle!(...)` |
| 61 | +//! |
59 | 62 | //! The `typle!` macro creates a new sequence of types or expressions. A |
60 | 63 | //! `typle!` macro can only appear where a comma-separated sequence is valid |
61 | 64 | //! (e.g. a tuple, array, argument list, or where clause). |
|
89 | 92 | //! assert_eq!(append((1, 2, 3), 4), (1, 2, 3, 4)); |
90 | 93 | //! ``` |
91 | 94 | //! |
| 95 | +//! # Constraints |
| 96 | +//! |
92 | 97 | //! Specify constraints on the tuple components using one of the following |
93 | 98 | //! forms. Except for the first form, these constraints can only appear in the |
94 | 99 | //! `where` clause. |
|
150 | 155 | //! |
151 | 156 | //! ``` |
152 | 157 | //! # use typle::typle; |
153 | | -//! #[typle(Tuple for 0..=12)] |
| 158 | +//! #[cfg_attr(not(feature = "big-tuple"), typle(Tuple for 0..=12))] |
| 159 | +//! #[cfg_attr(feature = "big-tuple", typle(Tuple for 0..=24))] |
154 | 160 | //! fn even_to_string<T: Tuple>( |
155 | 161 | //! t: T, |
156 | 162 | //! ) -> (typle!(i in .. => if i % 2 == 0 { String } else { T<{i}> })) |
|
165 | 171 | //! assert_eq!(even_to_string((0, vec![1], 2, 3)), ("0".to_owned(), vec![1], "2".to_owned(), 3)); |
166 | 172 | //! ``` |
167 | 173 | //! |
168 | | -//! If there is no range in the `typle!` macro, the body is evaluated once. This can be |
169 | | -//! useful in positions where an `if` expression is not permitted. |
170 | | -//! |
171 | 174 | //! The associated constant `LAST` is always equal to `LEN - 1`. This is convenient for cases where |
172 | | -//! the final component should be treated differently, such as avoiding an additional clone. Using |
173 | | -//! `LAST` for a zero-length tuple causes a compilation error. |
| 175 | +//! the final component should be treated differently, such as avoiding an additional clone. `LAST` |
| 176 | +//! is not defined when `LEN == 0` and will cause a compilation error. |
| 177 | +//! |
| 178 | +//! The `typle_const!` macro supports const-if on a boolean typle index expression. const-if allows |
| 179 | +//! conditional branches that do not compile, as long as the branch are `false` at compile-time. The |
| 180 | +//! following code compiles for `T::LEN == 0` because `T::LAST` appears in an `else` branch that is |
| 181 | +//! not compiled when `T::LEN == 0`. |
174 | 182 | //! |
175 | 183 | //! ``` |
176 | 184 | //! # use typle::typle; |
| 185 | +//! # #[derive(Clone)] |
| 186 | +//! # struct Input {} |
177 | 187 | //! trait HandleStuff { |
178 | | -//! type Input; |
179 | 188 | //! type Output; |
180 | 189 | //! |
181 | | -//! fn handle_stuff(&self, input: Self::Input) -> Self::Output; |
| 190 | +//! fn handle_stuff(&self, input: Input) -> Self::Output; |
182 | 191 | //! } |
183 | 192 | //! |
184 | 193 | //! struct MultipleHandlers<T> { |
185 | 194 | //! handlers: T, |
186 | 195 | //! } |
187 | 196 | //! |
188 | | -//! #[typle(Tuple for 1..=12)] |
189 | | -//! impl<T: Tuple, I> HandleStuff for MultipleHandlers<T> |
| 197 | +//! #[typle(Tuple for 0..=12)] |
| 198 | +//! impl<T> HandleStuff for MultipleHandlers<T> |
190 | 199 | //! where |
191 | | -//! T<_>: HandleStuff<Input = I>, |
192 | | -//! // Only require the Clone bound if there are two or more handlers |
193 | | -//! typle!(=> if T::LEN > 1 { I: Clone }): Tuple::Bounds, |
| 200 | +//! T: Tuple, |
| 201 | +//! T<_>: HandleStuff, |
194 | 202 | //! { |
195 | | -//! type Input = I; |
196 | 203 | //! type Output = (typle!(i in .. => T<{i}>::Output)); |
197 | 204 | //! |
198 | | -//! fn handle_stuff(&self, input: Self::Input) -> Self::Output { |
199 | | -//! ( |
200 | | -//! typle!(i in ..T::LAST => self.handlers[[i]].handle_stuff(input.clone())), |
201 | | -//! // Avoid expensive clone for the last handler. |
202 | | -//! self.handlers[[T::LAST]].handle_stuff(input), |
203 | | -//! ) |
| 205 | +//! // Return a tuple of output from each handler applied to the same input. |
| 206 | +//! fn handle_stuff(&self, input: Input) -> Self::Output { |
| 207 | +//! if typle_const!(T::LEN == 0) { |
| 208 | +//! () |
| 209 | +//! } else { |
| 210 | +//! ( |
| 211 | +//! typle!(i in ..T::LAST => self.handlers[[i]].handle_stuff(input.clone())), |
| 212 | +//! // Avoid expensive clone for the last handler. |
| 213 | +//! self.handlers[[T::LAST]].handle_stuff(input), |
| 214 | +//! ) |
| 215 | +//! } |
204 | 216 | //! } |
205 | 217 | //! } |
206 | 218 | //! ``` |
207 | 219 | //! |
| 220 | +//! Without `typle_const!` this code will fail to compile. When there is no compilation error |
| 221 | +//! `typle_const!` is not needed. With a constant condition the compiler will compile the false |
| 222 | +//! branch but will optimize it out. |
| 223 | +//! |
208 | 224 | //! # Iteration |
209 | 225 | //! |
210 | 226 | //! Use the `typle_index!` macro in a `for` loop to iterate over a range bounded |
|
297 | 313 | //! assert_eq!(('f',).wrapping_substring_at(12), "ff"); |
298 | 314 | //! ``` |
299 | 315 | //! |
300 | | -//! # enums |
| 316 | +//! # `enum` |
301 | 317 | //! |
302 | 318 | //! Applying `typle` to an `enum` implements the `enum` once for the maximum length only. |
303 | 319 | //! |
|
359 | 375 | //! example `S::<typle_ident!(3)>` becomes the identifier `S3`. This is mainly |
360 | 376 | //! used to refer to enum variants. |
361 | 377 | //! |
362 | | -//! The `typle_const!` macro supports const-if on a boolean typle index |
363 | | -//! expression. const-if allows branches that do not compile, as long as they |
364 | | -//! are `false` at compile-time. For example, this code compiles for `T::LEN == 4` |
365 | | -//! even though the variant `TupleSequenceState::S4` does not exist because the |
366 | | -//! branch that refers to it is not compiled when `(i == T::LAST)`. |
367 | | -//! |
368 | 378 | //! ```rust |
369 | 379 | //! # use typle::typle; |
370 | 380 | //! # pub trait Extract { |
|
0 commit comments