1 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
2 | |
3 | /*! |
4 | A library for to allow multiple return types by automatically generated enum. |
5 | |
6 | This crate is a procedural macro implementation of the features discussions |
7 | in [rust-lang/rfcs#2414]. This idea is also known as |
8 | ["Anonymous sum types"][rust-lang/rfcs#294]. |
9 | |
10 | This library provides the following attribute macros: |
11 | |
12 | - `#[auto_enum]` |
13 | |
14 | Parses syntax, creates the enum, inserts variants, and passes specified |
15 | traits to `#[enum_derive]`. |
16 | |
17 | - `#[enum_derive]` |
18 | |
19 | Implements specified traits to the enum. |
20 | |
21 | # `#[auto_enum]` |
22 | |
23 | `#[auto_enum]`'s basic feature is to wrap the value returned by the obvious |
24 | branches (`match`, `if`, `return`, etc..) by an enum that implemented the |
25 | specified traits. |
26 | |
27 | ```rust |
28 | use auto_enums::auto_enum; |
29 | |
30 | #[auto_enum(Iterator)] |
31 | fn foo(x: i32) -> impl Iterator<Item = i32> { |
32 | match x { |
33 | 0 => 1..10, |
34 | _ => vec![5, 10].into_iter(), |
35 | } |
36 | } |
37 | ``` |
38 | |
39 | `#[auto_enum]` generates code in two stages. |
40 | |
41 | First, `#[auto_enum]` will do the following. |
42 | |
43 | - parses syntax |
44 | - creates the enum |
45 | - inserts variants |
46 | |
47 | Code like this will be generated: |
48 | |
49 | ```rust |
50 | fn foo(x: i32) -> impl Iterator<Item = i32> { |
51 | #[::auto_enums::enum_derive(Iterator)] |
52 | enum __Enum1<__T1, __T2> { |
53 | __T1(__T1), |
54 | __T2(__T2), |
55 | } |
56 | |
57 | match x { |
58 | 0 => __Enum1::__T1(1..10), |
59 | _ => __Enum1::__T2(vec![5, 10].into_iter()), |
60 | } |
61 | } |
62 | ``` |
63 | |
64 | Next, `#[enum_derive]` implements the specified traits. |
65 | |
66 | <details> |
67 | <summary>Code like this will be generated:</summary> |
68 | |
69 | ```rust |
70 | fn foo(x: i32) -> impl Iterator<Item = i32> { |
71 | enum __Enum1<__T1, __T2> { |
72 | __T1(__T1), |
73 | __T2(__T2), |
74 | } |
75 | |
76 | impl<__T1, __T2> ::core::iter::Iterator for __Enum1<__T1, __T2> |
77 | where |
78 | __T1: ::core::iter::Iterator, |
79 | __T2: ::core::iter::Iterator<Item = <__T1 as ::core::iter::Iterator>::Item>, |
80 | { |
81 | type Item = <__T1 as ::core::iter::Iterator>::Item; |
82 | #[inline ] |
83 | fn next(&mut self) -> ::core::option::Option<Self::Item> { |
84 | match self { |
85 | __Enum1::__T1(x) => x.next(), |
86 | __Enum1::__T2(x) => x.next(), |
87 | } |
88 | } |
89 | #[inline ] |
90 | fn size_hint(&self) -> (usize, ::core::option::Option<usize>) { |
91 | match self { |
92 | __Enum1::__T1(x) => x.size_hint(), |
93 | __Enum1::__T2(x) => x.size_hint(), |
94 | } |
95 | } |
96 | } |
97 | |
98 | match x { |
99 | 0 => __Enum1::__T1(1..10), |
100 | _ => __Enum1::__T2(vec![5, 10].into_iter()), |
101 | } |
102 | } |
103 | ``` |
104 | |
105 | </details> |
106 | <br> |
107 | |
108 | ## Nested arms/branches |
109 | |
110 | `#[auto_enum]` can also parse nested arms/branches by using the `#[nested]` |
111 | attribute. |
112 | |
113 | ```rust |
114 | use auto_enums::auto_enum; |
115 | |
116 | #[auto_enum(Iterator)] |
117 | fn foo(x: i32) -> impl Iterator<Item = i32> { |
118 | match x { |
119 | 0 => 1..10, |
120 | #[nested] |
121 | _ => match x { |
122 | 1 => vec![5, 10].into_iter(), |
123 | _ => 0..=x, |
124 | }, |
125 | } |
126 | } |
127 | ``` |
128 | |
129 | `#[nested]` can be used basically in the same place as `#[auto_enum]`, |
130 | except that `#[nested]` cannot be used in functions. |
131 | |
132 | ## Recursion |
133 | |
134 | If an error due to recursion occurs, you need to box branches where recursion occurs. |
135 | |
136 | ```rust |
137 | use auto_enums::auto_enum; |
138 | |
139 | struct Type { |
140 | child: Vec<Type>, |
141 | } |
142 | |
143 | impl Type { |
144 | #[auto_enum(Iterator)] |
145 | fn method(&self) -> impl Iterator<Item = ()> + '_ { |
146 | if self.child.is_empty() { |
147 | Some(()).into_iter() |
148 | } else { |
149 | // Boxing is only needed on branches where recursion occurs. |
150 | Box::new(self.child.iter().flat_map(|c| c.method())) as Box<dyn Iterator<Item = _>> |
151 | } |
152 | } |
153 | } |
154 | ``` |
155 | |
156 | ## Positions where `#[auto_enum]` can be used. |
157 | |
158 | `#[auto_enum]` can be used in the following three places. However, since |
159 | [stmt_expr_attributes] and [proc_macro_hygiene] are not stabilized, you need |
160 | to use empty `#[auto_enum]` for functions except nightly. |
161 | |
162 | [stmt_expr_attributes]: https://github.com/rust-lang/rust/issues/15701 |
163 | [proc_macro_hygiene]: https://github.com/rust-lang/rust/issues/54727 |
164 | |
165 | - functions |
166 | |
167 | ```rust |
168 | use auto_enums::auto_enum; |
169 | |
170 | #[auto_enum(Iterator)] |
171 | fn func(x: i32) -> impl Iterator<Item=i32> { |
172 | if x == 0 { |
173 | Some(0).into_iter() |
174 | } else { |
175 | 0..x |
176 | } |
177 | } |
178 | ``` |
179 | |
180 | - expressions |
181 | |
182 | ```rust |
183 | use auto_enums::auto_enum; |
184 | |
185 | #[auto_enum] // Nightly does not need an empty attribute to the function. |
186 | fn expr(x: i32) -> impl Iterator<Item=i32> { |
187 | #[auto_enum(Iterator)] |
188 | match x { |
189 | 0 => Some(0).into_iter(), |
190 | _ => 0..x, |
191 | } |
192 | } |
193 | ``` |
194 | |
195 | - let binding |
196 | |
197 | ```rust |
198 | use auto_enums::auto_enum; |
199 | |
200 | #[auto_enum] // Nightly does not need an empty attribute to the function. |
201 | fn let_binding(x: i32) -> impl Iterator<Item=i32> { |
202 | #[auto_enum(Iterator)] |
203 | let iter = match x { |
204 | 0 => Some(0).into_iter(), |
205 | _ => 0..x, |
206 | }; |
207 | iter |
208 | } |
209 | ``` |
210 | |
211 | ## Supported syntax |
212 | |
213 | - `if` and `match` |
214 | |
215 | Wrap each branch with a variant. |
216 | |
217 | ```rust |
218 | use auto_enums::auto_enum; |
219 | |
220 | // if |
221 | #[auto_enum(Iterator)] |
222 | fn expr_if(x: i32) -> impl Iterator<Item=i32> { |
223 | if x == 0 { |
224 | Some(0).into_iter() |
225 | } else { |
226 | 0..x |
227 | } |
228 | } |
229 | |
230 | // match |
231 | #[auto_enum] // Nightly does not need an empty attribute to the function. |
232 | fn expr_match(x: i32) -> impl Iterator<Item=i32> { |
233 | #[auto_enum(Iterator)] |
234 | let iter = match x { |
235 | 0 => Some(0).into_iter(), |
236 | _ => 0..x, |
237 | }; |
238 | iter |
239 | } |
240 | ``` |
241 | |
242 | - `loop` |
243 | |
244 | Wrap each `break` with a variant. Nested loops and labeled `break` are |
245 | also supported. |
246 | |
247 | ```rust |
248 | use auto_enums::auto_enum; |
249 | |
250 | #[auto_enum(Iterator)] |
251 | fn expr_loop(mut x: i32) -> impl Iterator<Item = i32> { |
252 | loop { |
253 | if x < 0 { |
254 | break x..0; |
255 | } else if x % 5 == 0 { |
256 | break 0..=x; |
257 | } |
258 | x -= 1; |
259 | } |
260 | } |
261 | ``` |
262 | |
263 | - `return` (in functions) |
264 | |
265 | `#[auto_enum]` can parse the `return` in the scope. |
266 | |
267 | This analysis is valid only when the return type is `impl Trait`. |
268 | |
269 | ```rust |
270 | use auto_enums::auto_enum; |
271 | |
272 | // return (in functions) |
273 | #[auto_enum(Iterator)] |
274 | fn func(x: i32) -> impl Iterator<Item=i32> { |
275 | if x == 0 { |
276 | return Some(0).into_iter(); |
277 | } |
278 | |
279 | if x > 0 { |
280 | 0..x |
281 | } else { |
282 | x..=0 |
283 | } |
284 | } |
285 | ``` |
286 | |
287 | - `return` (in closures) |
288 | |
289 | `#[auto_enum]` can parse the `return` in the scope. |
290 | |
291 | This analysis is valid only when the following two conditions are satisfied. |
292 | |
293 | - `#[auto_enum]` must be used directly for that closure (or the let binding of the closure). |
294 | - `?` operator not used in the scope. |
295 | |
296 | ```rust |
297 | use auto_enums::auto_enum; |
298 | |
299 | // return (in closures) |
300 | #[auto_enum] // Nightly does not need an empty attribute to the function. |
301 | fn closure() -> impl Iterator<Item=i32> { |
302 | #[auto_enum(Iterator)] |
303 | let f = |x| { |
304 | if x == 0 { |
305 | return Some(0).into_iter(); |
306 | } |
307 | |
308 | if x > 0 { |
309 | 0..x |
310 | } else { |
311 | x..=0 |
312 | } |
313 | }; |
314 | f(1) |
315 | } |
316 | ``` |
317 | |
318 | - `?` operator (in functions) |
319 | |
320 | `#[auto_enum]` can parse the `?` operator in the scope. |
321 | |
322 | This analysis is valid only when the return type is `Result<T, impl Trait>`. |
323 | |
324 | ```rust |
325 | use auto_enums::auto_enum; |
326 | use std::fmt::{Debug, Display}; |
327 | |
328 | // `?` operator (in functions) |
329 | #[auto_enum(Debug, Display)] |
330 | fn func(x: i32) -> Result<i32, impl Debug + Display> { |
331 | if x == 0 { |
332 | Err("`x` is zero" )?; |
333 | } |
334 | |
335 | // The last branch of the function is not parsed. |
336 | if x < 0 { |
337 | Err(x)? |
338 | } else { |
339 | Ok(x + 1) |
340 | } |
341 | } |
342 | ``` |
343 | |
344 | `?` operator is expanded as follows: |
345 | |
346 | ```rust |
347 | # enum Enum<A> { Variant(A) } |
348 | # fn dox<T, E>(expr: Result<T, E>) -> Result<T, Enum<E>> { |
349 | # Ok( |
350 | match expr { |
351 | Ok(val) => val, |
352 | Err(err) => return Err(Enum::Variant(err)), |
353 | } |
354 | # ) |
355 | # } |
356 | ``` |
357 | |
358 | - `?` operator (in closures) |
359 | |
360 | `#[auto_enum]` can parse the `?` operator in the scope. |
361 | |
362 | However, `#[auto_enum]` must be used directly for that closure |
363 | (or the let binding of the closure). |
364 | |
365 | ```rust |
366 | use auto_enums::auto_enum; |
367 | use std::fmt::{Debug, Display}; |
368 | |
369 | // `?` operator (in closures) |
370 | #[auto_enum] // Nightly does not need an empty attribute to the function. |
371 | fn closure() -> Result<i32, impl Debug + Display> { |
372 | #[auto_enum(Debug, Display)] |
373 | let f = |x| { |
374 | if x == 0 { |
375 | Err("`x` is zero" )? |
376 | } |
377 | |
378 | // The last branch of the function is not interpreted as a branch. |
379 | if x < 0 { |
380 | Err(x)? |
381 | } else { |
382 | Ok(x + 1) |
383 | } |
384 | }; |
385 | f(1) |
386 | } |
387 | ``` |
388 | |
389 | - Block, unsafe block, method call, parentheses, and type ascription |
390 | |
391 | The following expressions are recursively searched until an `if`, `match`, |
392 | `loop` or unsupported expression is found. |
393 | |
394 | - blocks |
395 | - unsafe blocks |
396 | - method calls |
397 | - parentheses |
398 | - type ascriptions |
399 | |
400 | ```rust |
401 | use auto_enums::auto_enum; |
402 | |
403 | // block |
404 | #[auto_enum] // Nightly does not need an empty attribute to the function. |
405 | fn expr_block(x: i32) -> impl Iterator<Item=i32> { |
406 | #[auto_enum(Iterator)] |
407 | { |
408 | if x == 0 { |
409 | Some(0).into_iter() |
410 | } else { |
411 | 0..x |
412 | } |
413 | } |
414 | } |
415 | |
416 | // method call |
417 | #[auto_enum] // Nightly does not need an empty attribute to the function. |
418 | fn expr_method(x: i32) -> impl Iterator<Item=i32> { |
419 | #[auto_enum(Iterator)] |
420 | match x { |
421 | 0 => Some(0).into_iter(), |
422 | _ => 0..x, |
423 | }.map(|y| y + 1) |
424 | } |
425 | |
426 | // parentheses |
427 | # #[allow (unused_parens)] |
428 | #[auto_enum(Iterator)] |
429 | fn expr_parentheses(x: i32) -> impl Iterator<Item=i32> { |
430 | (if x == 0 { Some(0).into_iter() } else { 0..x }) |
431 | } |
432 | ``` |
433 | |
434 | ## Expression that no value will be returned |
435 | |
436 | If the last expression of a branch is one of the following, it is |
437 | interpreted that no value will be returned (variant assignment is skipped). |
438 | |
439 | - `panic!(..)` |
440 | - `unreachable!(..)` |
441 | - `return` |
442 | - `break` |
443 | - `continue` |
444 | - `None?` |
445 | - `Err(..)?` |
446 | - Expression level marker (`marker!` macro). |
447 | - An item definition. |
448 | |
449 | Also, if the branch contains `#[nested]`, it is interpreted as returning |
450 | an anonymous enum generated by `#[auto_enum]`, not a value. |
451 | |
452 | ```rust |
453 | use auto_enums::auto_enum; |
454 | |
455 | #[auto_enum(Iterator)] |
456 | fn foo(x: i32) -> impl Iterator<Item = i32> { |
457 | match x { |
458 | 0 => 1..10, |
459 | 1 => panic!(), // variant assignment is skipped |
460 | _ => vec![5, 10].into_iter(), |
461 | } |
462 | } |
463 | ``` |
464 | |
465 | You can also skip that branch explicitly by `#[never]` attribute. |
466 | |
467 | ```rust |
468 | use auto_enums::auto_enum; |
469 | |
470 | #[auto_enum(Iterator)] |
471 | fn foo(x: i32) -> impl Iterator<Item = i32> { |
472 | match x { |
473 | 0 => 1..10, |
474 | #[never] |
475 | 1 => loop { |
476 | panic!() |
477 | }, |
478 | _ => vec![5, 10].into_iter(), |
479 | } |
480 | } |
481 | ``` |
482 | |
483 | ## Expression level marker (`marker!` macro) |
484 | |
485 | `#[auto_enum]` replaces `marker!` macros with variants. |
486 | If values of two or more are specified by `marker!` macros, `#[auto_enum]` |
487 | can be used for unsupported expressions and statements. |
488 | |
489 | ```rust |
490 | use auto_enums::auto_enum; |
491 | |
492 | #[auto_enum(Iterator)] |
493 | fn foo(x: i32) -> impl Iterator<Item = i32> { |
494 | if x < 0 { |
495 | return x..=0; |
496 | } |
497 | marker!(1..10) |
498 | } |
499 | ``` |
500 | |
501 | The default name of the macro is `"marker"`, but you can change it by |
502 | `marker` option. |
503 | |
504 | ```rust |
505 | use auto_enums::auto_enum; |
506 | |
507 | #[auto_enum(marker = bar, Iterator)] |
508 | fn foo(x: i32) -> impl Iterator<Item = i32> { |
509 | if x < 0 { |
510 | return x..=0; |
511 | } |
512 | bar!(1..10) |
513 | } |
514 | ``` |
515 | |
516 | ## Rust Nightly |
517 | |
518 | When using `#[auto_enum]` for expressions and statements, `#[auto_enum]` for |
519 | function is unnecessary. |
520 | |
521 | ```rust |
522 | // Add this to your crate root: |
523 | #![feature(proc_macro_hygiene, stmt_expr_attributes)] |
524 | ``` |
525 | |
526 | ```rust |
527 | # #![feature(proc_macro_hygiene, stmt_expr_attributes)] |
528 | use auto_enums::auto_enum; |
529 | |
530 | fn foo(x: i32) -> i32 { |
531 | #[auto_enum(Iterator)] |
532 | let iter = match x { |
533 | 0 => 1..10, |
534 | _ => vec![5, 10].into_iter(), |
535 | }; |
536 | |
537 | iter.fold(0, |sum, x| sum + x) |
538 | } |
539 | ``` |
540 | |
541 | You can also return closures. |
542 | |
543 | ```rust |
544 | // Add this to your crate root: |
545 | #![feature(fn_traits, unboxed_closures)] |
546 | ``` |
547 | |
548 | ```rust |
549 | # #![feature(fn_traits, unboxed_closures)] |
550 | use auto_enums::auto_enum; |
551 | |
552 | #[auto_enum(Fn)] |
553 | fn foo(x: bool) -> impl Fn(i32) -> i32 { |
554 | if x { |
555 | |y| y + 1 |
556 | } else { |
557 | |z| z - 1 |
558 | } |
559 | } |
560 | ``` |
561 | |
562 | # `#[enum_derive]` |
563 | |
564 | `#[enum_derive]` implements the supported traits and passes unsupported |
565 | traits to `#[derive]`. |
566 | |
567 | If you want to use traits that are not supported by `#[enum_derive]`, you |
568 | can use another crate that provides [derives macros][proc-macro-derive], or |
569 | you can define derives macros yourself ([derive_utils] probably can help it). |
570 | |
571 | Basic usage of `#[enum_derive]` |
572 | |
573 | ```rust |
574 | use auto_enums::enum_derive; |
575 | |
576 | // `#[enum_derive]` implements `Iterator`, and `#[derive]` implements `Clone`. |
577 | #[enum_derive(Iterator, Clone)] |
578 | enum Foo<A, B> { |
579 | A(A), |
580 | B(B), |
581 | } |
582 | ``` |
583 | |
584 | `#[enum_derive]` adds the dependency of the specified trait if it is not |
585 | specified. |
586 | |
587 | ```rust |
588 | use auto_enums::enum_derive; |
589 | |
590 | // `#[enum_derive]` implements `Iterator` and `ExactSizeIterator`. |
591 | #[enum_derive(ExactSizeIterator)] |
592 | enum Foo<A, B> { |
593 | A(A), |
594 | B(B), |
595 | } |
596 | ``` |
597 | |
598 | [derive_utils]: https://github.com/taiki-e/derive_utils |
599 | |
600 | # Supported traits |
601 | |
602 | Some traits support is disabled by default. |
603 | Note that some traits have aliases. |
604 | |
605 | *When using features that depend on unstable APIs, the `unstable` feature must be explicitly enabled* |
606 | |
607 | ## The standard library (`std`, `core`) |
608 | |
609 | ### `[std|core]::iter` |
610 | |
611 | - [`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/iterator.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/iterator.expanded.rs) |
612 | - [`DoubleEndedIterator`](https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/double_ended_iterator.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/double_ended_iterator.expanded.rs) |
613 | - [`ExactSizeIterator`](https://doc.rust-lang.org/std/iter/trait.ExactSizeIterator.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/exact_size_iterator.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/exact_size_iterator.expanded.rs) |
614 | - [`FusedIterator`](https://doc.rust-lang.org/std/iter/trait.FusedIterator.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/fused_iterator.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/fused_iterator.expanded.rs) |
615 | - [`Extend`](https://doc.rust-lang.org/std/iter/trait.Extend.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/extend.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/extend.expanded.rs) |
616 | - [`TrustedLen`](https://doc.rust-lang.org/std/iter/trait.TrustedLen.html) *(requires `"trusted_len"` and `"unstable"` crate features)* - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/trusted_len.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/iter/trusted_len.expanded.rs) |
617 | |
618 | *See also [iter-enum] crate.* |
619 | |
620 | ### `[std|core]::future` |
621 | |
622 | - [`Future`](https://doc.rust-lang.org/std/future/trait.Future.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/future.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/future.expanded.rs) |
623 | |
624 | ### `std::io` *(requires `"std"` crate feature)* |
625 | |
626 | - [`Read`](https://doc.rust-lang.org/std/io/trait.Read.html) (alias: `io::Read`) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/io/read.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/io/read.expanded.rs) |
627 | - [`BufRead`](https://doc.rust-lang.org/std/io/trait.BufRead.html) (alias: `io::BufRead`) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/io/buf_read.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/io/buf_read.expanded.rs) |
628 | - [`Write`](https://doc.rust-lang.org/std/io/trait.Write.html) (alias: `io::Write`) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/io/write.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/io/write.expanded.rs) |
629 | - [`Seek`](https://doc.rust-lang.org/std/io/trait.Seek.html) (alias: `io::Seek`) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/io/seek.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/io/seek.expanded.rs) |
630 | |
631 | *See also [io-enum] crate.* |
632 | |
633 | ### `[std|core]::ops` |
634 | |
635 | - [`Deref`](https://doc.rust-lang.org/std/ops/trait.Deref.html) *(requires `"ops"` crate feature)* |
636 | - [`DerefMut`](https://doc.rust-lang.org/std/ops/trait.DerefMut.html) *(requires `"ops"` crate feature)* |
637 | - [`Index`](https://doc.rust-lang.org/std/ops/trait.Index.html) *(requires `"ops"` crate feature)* |
638 | - [`IndexMut`](https://doc.rust-lang.org/std/ops/trait.IndexMut.html) *(requires `"ops"` crate feature)* |
639 | - [`RangeBounds`](https://doc.rust-lang.org/std/ops/trait.RangeBounds.html) *(requires `"ops"` crate feature)* |
640 | - [`Fn`](https://doc.rust-lang.org/std/ops/trait.Fn.html) *(requires `"fn_traits"` and `"unstable"` crate features)* |
641 | - [`FnMut`](https://doc.rust-lang.org/std/ops/trait.FnMut.html) *(requires `"fn_traits"` and `"unstable"` crate features)* |
642 | - [`FnOnce`](https://doc.rust-lang.org/std/ops/trait.FnOnce.html) *(requires `"fn_traits"` and `"unstable"` crate features)* |
643 | - [`Coroutine`](https://doc.rust-lang.org/nightly/std/ops/trait.Coroutine.html) *(requires `"coroutine_trait"` and `"unstable"` crate features)* |
644 | |
645 | ### `[std|core]::convert` |
646 | |
647 | - [`AsRef`](https://doc.rust-lang.org/std/convert/trait.AsRef.html) *(requires `"convert"` crate feature)* |
648 | - [`AsMut`](https://doc.rust-lang.org/std/convert/trait.AsMut.html) *(requires `"convert"` crate feature)* |
649 | |
650 | ### `[std|core]::fmt` |
651 | |
652 | - [`Debug`](https://doc.rust-lang.org/std/fmt/trait.Debug.html) (alias: `fmt::Debug`) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/debug.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/debug.expanded.rs) |
653 | - [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html) (alias: `fmt::Display`) |
654 | - [`fmt::Binary`](https://doc.rust-lang.org/std/fmt/trait.Binary.html) *(requires `"fmt"` crate feature)* |
655 | - [`fmt::LowerExp`](https://doc.rust-lang.org/std/fmt/trait.LowerExp.html) *(requires `"fmt"` crate feature)* |
656 | - [`fmt::LowerHex`](https://doc.rust-lang.org/std/fmt/trait.LowerHex.html) *(requires `"fmt"` crate feature)* |
657 | - [`fmt::Octal`](https://doc.rust-lang.org/std/fmt/trait.Octal.html) *(requires `"fmt"` crate feature)* |
658 | - [`fmt::Pointer`](https://doc.rust-lang.org/std/fmt/trait.Pointer.html) *(requires `"fmt"` crate feature)* |
659 | - [`fmt::UpperExp`](https://doc.rust-lang.org/std/fmt/trait.UpperExp.html) *(requires `"fmt"` crate feature)* |
660 | - [`fmt::UpperHex`](https://doc.rust-lang.org/std/fmt/trait.UpperHex.html) *(requires `"fmt"` crate feature)* |
661 | - [`fmt::Write`](https://doc.rust-lang.org/std/fmt/trait.Write.html) |
662 | |
663 | ### `std::error` *(requires `"std"` crate feature)* |
664 | |
665 | - [`Error`](https://doc.rust-lang.org/std/error/trait.Error.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/error.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/std/error.expanded.rs) |
666 | |
667 | ## External libraries |
668 | |
669 | You can use support for external library traits by activating each crate feature. |
670 | |
671 | To use support for external library traits, you need to use the path starting with the feature name. For example: |
672 | |
673 | ```rust |
674 | # extern crate rayon_crate as rayon; |
675 | use auto_enums::auto_enum; |
676 | use rayon::prelude::*; |
677 | |
678 | #[auto_enum(rayon::ParallelIterator)] // Note that this is not `#[auto_enum(ParallelIterator)]` |
679 | fn func(x: i32) -> impl ParallelIterator { |
680 | match x { |
681 | 0 => (1..10).into_par_iter(), |
682 | _ => vec![5, 10].into_par_iter(), |
683 | } |
684 | } |
685 | ``` |
686 | |
687 | ### [futures v0.3][futures03] *(requires `"futures03"` crate feature)* |
688 | |
689 | - [`futures03::Stream`](https://docs.rs/futures/0.3/futures/stream/trait.Stream.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/stream.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/stream.expanded.rs) |
690 | - [`futures03::Sink`](https://docs.rs/futures/0.3/futures/sink/trait.Sink.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/sink.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/sink.expanded.rs) |
691 | - [`futures03::AsyncRead`](https://docs.rs/futures/0.3/futures/io/trait.AsyncRead.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/async_read.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/async_read.expanded.rs) |
692 | - [`futures03::AsyncWrite`](https://docs.rs/futures/0.3/futures/io/trait.AsyncWrite.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/async_write.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/async_write.expanded.rs) |
693 | - [`futures03::AsyncSeek`](https://docs.rs/futures/0.3/futures/io/trait.AsyncSeek.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/async_seek.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/async_seek.expanded.rs) |
694 | - [`futures03::AsyncBufRead`](https://docs.rs/futures/0.3/futures/io/trait.AsyncBufRead.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/async_buf_read.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/futures/async_buf_read.expanded.rs) |
695 | |
696 | ### [futures v0.1][futures01] *(requires `"futures01"` crate feature)* |
697 | |
698 | - [`futures01::Future`](https://docs.rs/futures/0.1/futures/future/trait.Future.html) |
699 | - [`futures01::Stream`](https://docs.rs/futures/0.1/futures/stream/trait.Stream.html) |
700 | - [`futures01::Sink`](https://docs.rs/futures/0.1/futures/sink/trait.Sink.html) |
701 | |
702 | ### [rayon] *(requires `"rayon"` crate feature)* |
703 | |
704 | - [`rayon::ParallelIterator`](https://docs.rs/rayon/1/rayon/iter/trait.ParallelIterator.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/rayon/parallel_iterator.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/rayon/parallel_iterator.expanded.rs) |
705 | - [`rayon::IndexedParallelIterator`](https://docs.rs/rayon/1/rayon/iter/trait.IndexedParallelIterator.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/rayon/indexed_parallel_iterator.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/rayon/indexed_parallel_iterator.expanded.rs) |
706 | - [`rayon::ParallelExtend`](https://docs.rs/rayon/1/rayon/iter/trait.ParallelExtend.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/rayon/parallel_extend.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/rayon/parallel_extend.expanded.rs) |
707 | |
708 | ### [serde] *(requires `"serde"` crate feature)* |
709 | |
710 | - [`serde::Serialize`](https://docs.rs/serde/1/serde/trait.Serialize.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/serde/serialize.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/serde/serialize.expanded.rs) |
711 | |
712 | ### [tokio v1][tokio1] *(requires `"tokio1"` crate feature)* |
713 | |
714 | - [`tokio1::AsyncRead`](https://docs.rs/tokio/1/tokio/io/trait.AsyncRead.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/tokio/async_read.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/tokio/async_read.expanded.rs) |
715 | - [`tokio1::AsyncWrite`](https://docs.rs/tokio/1/tokio/io/trait.AsyncWrite.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/tokio/async_write.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/tokio/async_write.expanded.rs) |
716 | - [`tokio1::AsyncSeek`](https://docs.rs/tokio/1/tokio/io/trait.AsyncSeek.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/tokio/async_seek.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/tokio/async_seek.expanded.rs) |
717 | - [`tokio1::AsyncBufRead`](https://docs.rs/tokio/1/tokio/io/trait.AsyncBufRead.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/tokio/async_buf_read.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/tokio/async_buf_read.expanded.rs) |
718 | |
719 | ### [tokio v0.3][tokio03] *(requires `"tokio03"` crate feature)* |
720 | |
721 | - [`tokio03::AsyncRead`](https://docs.rs/tokio/0.3/tokio/io/trait.AsyncRead.html) |
722 | - [`tokio03::AsyncWrite`](https://docs.rs/tokio/0.3/tokio/io/trait.AsyncWrite.html) |
723 | - [`tokio03::AsyncSeek`](https://docs.rs/tokio/0.3/tokio/io/trait.AsyncSeek.html) |
724 | - [`tokio03::AsyncBufRead`](https://docs.rs/tokio/0.3/tokio/io/trait.AsyncBufRead.html) |
725 | |
726 | ### [tokio v0.2][tokio02] *(requires `"tokio02"` crate feature)* |
727 | |
728 | - [`tokio02::AsyncRead`](https://docs.rs/tokio/0.2/tokio/io/trait.AsyncRead.html) |
729 | - [`tokio02::AsyncWrite`](https://docs.rs/tokio/0.2/tokio/io/trait.AsyncWrite.html) |
730 | - [`tokio02::AsyncSeek`](https://docs.rs/tokio/0.2/tokio/io/trait.AsyncSeek.html) |
731 | - [`tokio02::AsyncBufRead`](https://docs.rs/tokio/0.2/tokio/io/trait.AsyncBufRead.html) |
732 | |
733 | ### [tokio v0.1][tokio01] *(requires `"tokio01"` crate feature)* |
734 | |
735 | - [`tokio01::AsyncRead`](https://docs.rs/tokio/0.1/tokio/io/trait.AsyncRead.html) |
736 | - [`tokio01::AsyncWrite`](https://docs.rs/tokio/0.1/tokio/io/trait.AsyncWrite.html) |
737 | |
738 | ### [http_body v1][http_body1] *(requires `"http_body1"` crate feature)* |
739 | |
740 | - [`http_body1::Body`](https://docs.rs/http-body/1/http_body/trait.Body.html) - [example](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/http_body/body.rs) | [generated code](https://github.com/taiki-e/auto_enums/blob/HEAD/tests/expand/external/http_body/body.expanded.rs) |
741 | |
742 | ## Inherent methods |
743 | |
744 | These don't derive traits, but derive inherent methods instead. |
745 | |
746 | - `Transpose` *(requires `"transpose_methods"` crate feature)* - this derives the following conversion methods. |
747 | |
748 | - `transpose` — convert from `enum<Option<T1>,..>` to `Option<enum<T1,..>>` |
749 | |
750 | - `transpose` — convert from `enum<Result<T1, E1>,..>` to `Result<enum<T1,..>, enum<E1,..>>` |
751 | |
752 | - `transpose_ok` — convert from `enum<Result<T1, E>,..>` to `Option<enum<T1,..>, E>` |
753 | |
754 | Examples: |
755 | |
756 | ```rust |
757 | use auto_enums::auto_enum; |
758 | use std::{fs::File, io, path::Path}; |
759 | |
760 | #[auto_enum(Transpose, Write)] |
761 | fn output_stream(file: Option<&Path>) -> io::Result<impl io::Write> { |
762 | match file { |
763 | Some(f) => File::create(f), |
764 | None => Ok(io::stdout()), |
765 | }.transpose_ok() |
766 | } |
767 | ``` |
768 | |
769 | - `transpose_err` — convert from `enum<Result<T, E1>,..>` to `Result<T, enum<E1,..>>` |
770 | |
771 | # Optional features |
772 | |
773 | - **`std`** *(enabled by default)* |
774 | - Enable to use `std` library's traits. |
775 | - **`ops`** |
776 | - Enable to use `[std|core]::ops`'s `Deref`, `DerefMut`, `Index`, `IndexMut`, and `RangeBounds` traits. |
777 | - **`convert`** |
778 | - Enable to use `[std|core]::convert`'s `AsRef` and `AsMut` traits. |
779 | - **`fmt`** |
780 | - Enable to use `[std|core]::fmt`'s traits other than `Debug`, `Display` and `Write`. |
781 | - **`transpose_methods`** |
782 | - Enable to use `transpose*` methods. |
783 | - **`futures03`** |
784 | - Enable to use [futures v0.3][futures03] traits. |
785 | - **`futures01`** |
786 | - Enable to use [futures v0.1][futures01] traits. |
787 | - **`rayon`** |
788 | - Enable to use [rayon] traits. |
789 | - **`serde`** |
790 | - Enable to use [serde] traits. |
791 | - **`tokio1`** |
792 | - Enable to use [tokio v1][tokio1] traits. |
793 | - **`tokio03`** |
794 | - Enable to use [tokio v0.3][tokio03] traits. |
795 | - **`tokio02`** |
796 | - Enable to use [tokio v0.2][tokio02] traits. |
797 | - **`tokio01`** |
798 | - Enable to use [tokio v0.1][tokio01] traits. |
799 | - **`http_body1`** |
800 | - Enable to use [http_body v1][http_body1] traits. |
801 | - **`coroutine_trait`** |
802 | - Enable to use `[std|core]::ops::Coroutine` trait. |
803 | - Note that this feature is unstable and may cause incompatible changes between patch versions. |
804 | - **`fn_traits`** |
805 | - Enable to use `[std|core]::ops`'s `Fn`, `FnMut`, and `FnOnce` traits. |
806 | - Note that this feature is unstable and may cause incompatible changes between patch versions. |
807 | - **`trusted_len`** |
808 | - Enable to use `[std|core]::iter::TrustedLen` trait. |
809 | - Note that this feature is unstable and may cause incompatible changes between patch versions. |
810 | |
811 | ## `type_analysis` feature |
812 | |
813 | Analyze return type of function and `let` binding. |
814 | |
815 | *Note that this feature is still experimental.* |
816 | |
817 | Examples: |
818 | |
819 | ```rust |
820 | use auto_enums::auto_enum; |
821 | |
822 | #[auto_enum] // there is no need to specify std library's traits |
823 | fn func1(x: i32) -> impl Iterator<Item = i32> { |
824 | match x { |
825 | 0 => 1..10, |
826 | _ => vec![5, 10].into_iter(), |
827 | } |
828 | } |
829 | |
830 | #[auto_enum] |
831 | fn func2(x: i32) { |
832 | // Unlike `feature(impl_trait_in_bindings)`, this works on stable compilers. |
833 | #[auto_enum] |
834 | let iter: impl Iterator<Item = i32> = match x { |
835 | 0 => Some(0).into_iter(), |
836 | _ => 0..x, |
837 | }; |
838 | } |
839 | ``` |
840 | |
841 | Please be careful if you return another traits with the same name. |
842 | |
843 | # Known limitations |
844 | |
845 | - There needs to explicitly specify the trait to be implemented (`type_analysis` crate feature reduces this limitation). |
846 | - There needs to be marker macros for unsupported expressions. |
847 | |
848 | ## Related Projects |
849 | |
850 | - [derive_utils]: A procedural macro helper for easily writing [derives macros][proc-macro-derive] for enums. |
851 | - [io-enum]: \#\[derive(Read, Write, Seek, BufRead)\] for enums. |
852 | - [iter-enum]: \#\[derive(Iterator, DoubleEndedIterator, ExactSizeIterator, Extend)\] for enums. |
853 | |
854 | [derive_utils]: https://github.com/taiki-e/derive_utils |
855 | [futures01]: https://docs.rs/futures/0.1 |
856 | [futures03]: https://docs.rs/futures/0.3 |
857 | [io-enum]: https://github.com/taiki-e/io-enum |
858 | [iter-enum]: https://github.com/taiki-e/iter-enum |
859 | [proc-macro-derive]: https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros |
860 | [rayon]: https://docs.rs/rayon/1 |
861 | [rust-lang/rfcs#294]: https://github.com/rust-lang/rfcs/issues/294 |
862 | [rust-lang/rfcs#2414]: https://github.com/rust-lang/rfcs/issues/2414 |
863 | [serde]: https://docs.rs/serde/1 |
864 | [tokio01]: https://docs.rs/tokio/0.1 |
865 | [tokio02]: https://docs.rs/tokio/0.2 |
866 | [tokio03]: https://docs.rs/tokio/0.3 |
867 | [tokio1]: https://docs.rs/tokio/1 |
868 | [http_body1]: https://docs.rs/http-body/1 |
869 | */ |
870 | |
871 | #![doc (test( |
872 | no_crate_inject, |
873 | attr( |
874 | deny(warnings, rust_2018_idioms, single_use_lifetimes), |
875 | allow(dead_code, unused_variables) |
876 | ) |
877 | ))] |
878 | #![forbid (unsafe_code)] |
879 | #![allow (clippy::doc_link_with_quotes)] |
880 | |
881 | #[cfg (all(feature = "coroutine_trait" , not(feature = "unstable" )))] |
882 | compile_error!( |
883 | "The `coroutine_trait` feature requires the `unstable` feature as an explicit opt-in to unstable features" |
884 | ); |
885 | |
886 | #[cfg (all(feature = "fn_traits" , not(feature = "unstable" )))] |
887 | compile_error!( |
888 | "The `fn_traits` feature requires the `unstable` feature as an explicit opt-in to unstable features" |
889 | ); |
890 | |
891 | #[cfg (all(feature = "trusted_len" , not(feature = "unstable" )))] |
892 | compile_error!( |
893 | "The `trusted_len` feature requires the `unstable` feature as an explicit opt-in to unstable features" |
894 | ); |
895 | |
896 | #[cfg (doctest)] |
897 | #[doc = include_str!("../README.md" )] |
898 | const _README: () = (); |
899 | |
900 | #[macro_use ] |
901 | mod error; |
902 | |
903 | mod auto_enum; |
904 | mod derive; |
905 | mod enum_derive; |
906 | mod utils; |
907 | |
908 | use proc_macro::TokenStream; |
909 | |
910 | /// An attribute macro like a wrapper of `#[derive]`, implementing |
911 | /// the supported traits and passing unsupported traits to `#[derive]`. |
912 | /// |
913 | /// See crate level documentation for details. |
914 | #[proc_macro_attribute ] |
915 | pub fn enum_derive (args: TokenStream, input: TokenStream) -> TokenStream { |
916 | crate::enum_derive::attribute(args:args.into(), input:input.into()).into() |
917 | } |
918 | |
919 | /// An attribute macro for to allow multiple return types by automatically generated enum. |
920 | /// |
921 | /// See crate level documentation for details. |
922 | #[proc_macro_attribute ] |
923 | pub fn auto_enum (args: TokenStream, input: TokenStream) -> TokenStream { |
924 | crate::auto_enum::attribute(args:args.into(), input:input.into()).into() |
925 | } |
926 | |