A library for to allow multiple return types by automatically generated enum.

This library provides the following attribute macros:

#[auto_enum] Parses syntax, creates the enum, inserts variants, and passes specified traits to #[enum_derive] .

#[enum_derive] Implements specified traits to the enum.

#[auto_enum] 's basic feature is to wrap the value returned by the obvious branches ( match , if , return , etc..) by an enum that implemented the specified traits.

use auto_enums :: auto_enum ; #[ auto_enum ( Iterator )] fn foo ( x : i32 ) - > impl Iterator < Item = i32 > { match x { 0 = > 1 .. 10 , _ = > vec ! [ 5 , 10 ]. into_iter (), } }

#[auto_enum] generates code in two stages.

First, #[auto_enum] will do the following.

parses syntax

creates the enum

inserts variants

Code like this will be generated:

fn foo ( x : i32 ) - > impl Iterator < Item = i32 > { #[:: auto_enums :: enum_derive ( Iterator )] enum __Enum1 < __T1 , __T2 > { __T1 ( __T1 ), __T2 ( __T2 ), } match x { 0 = > __Enum1 :: __T1 ( 1 .. 10 ), _ = > __Enum1 :: __T2 ( vec ! [ 5 , 10 ]. into_iter ()), } }

Next, #[enum_derive] implements the specified traits.

Code like this will be generated: fn foo ( x : i32 ) - > impl Iterator < Item = i32 > { enum __Enum1 < __T1 , __T2 > { __T1 ( __T1 ), __T2 ( __T2 ), } impl < __T1 , __T2 > :: core :: iter :: Iterator for __Enum1 < __T1 , __T2 > where __T1 : :: core :: iter :: Iterator , __T2 : :: core :: iter :: Iterator < Item = < __T1 as :: core :: iter :: Iterator > :: Item > , { type Item = < __T1 as :: core :: iter :: Iterator > :: Item ; #[ inline ] fn next ( & mut self ) - > :: core :: option :: Option < Self :: Item > { match self { __Enum1 :: __T1 ( x ) = > x . next (), __Enum1 :: __T2 ( x ) = > x . next (), } } #[ inline ] fn size_hint ( & self ) - > ( usize , :: core :: option :: Option < usize > ) { match self { __Enum1 :: __T1 ( x ) = > x . size_hint (), __Enum1 :: __T2 ( x ) = > x . size_hint (), } } } match x { 0 = > __Enum1 :: __T1 ( 1 .. 10 ), _ = > __Enum1 :: __T2 ( vec ! [ 5 , 10 ]. into_iter ()), } }

#[auto_enum] can also parse nested arms/branches by using the #[nested] attribute.

use auto_enums :: auto_enum ; #[ auto_enum ( Iterator )] fn foo ( x : i32 ) - > impl Iterator < Item = i32 > { match x { 0 = > 1 .. 10 , #[ nested ] _ = > match x { 1 = > vec ! [ 5 , 10 ]. into_iter (), _ = > 0 .. = x , }, } }

#[nested] can be used basically in the same place as #[auto_enum] , except that #[nested] cannot be used in functions.

#[auto_enum] can be used in the following three places. However, since stmt_expr_attributes and proc_macro_hygiene are not stabilized, you need to use empty #[auto_enum] for functions except nightly.

functions use auto_enums :: auto_enum ; #[ auto_enum ( Iterator )] fn func ( x : i32 ) - > impl Iterator < Item = i32 > { if x = = 0 { Some ( 0 ). into_iter () } else { 0 .. x } }

expressions use auto_enums :: auto_enum ; #[ auto_enum ] fn expr ( x : i32 ) - > impl Iterator < Item = i32 > { #[ auto_enum ( Iterator )] match x { 0 = > Some ( 0 ). into_iter (), _ = > 0 .. x , } }

let binding use auto_enums :: auto_enum ; #[ auto_enum ] fn let_binding ( x : i32 ) - > impl Iterator < Item = i32 > { #[ auto_enum ( Iterator )] let iter = match x { 0 = > Some ( 0 ). into_iter (), _ = > 0 .. x , }; iter }

if and match Wrap each branch with a variant. use auto_enums :: auto_enum ; #[ auto_enum ( Iterator )] fn expr_if ( x : i32 ) - > impl Iterator < Item = i32 > { if x = = 0 { Some ( 0 ). into_iter () } else { 0 .. x } } #[ auto_enum ] fn expr_match ( x : i32 ) - > impl Iterator < Item = i32 > { #[ auto_enum ( Iterator )] let iter = match x { 0 = > Some ( 0 ). into_iter (), _ = > 0 .. x , }; iter }

loop Wrap each break with a variant. Nested loops and labeled break are also supported. use auto_enums :: auto_enum ; #[ auto_enum ( Iterator )] fn expr_loop ( mut x : i32 ) - > impl Iterator < Item = i32 > { loop { if x < 0 { break x .. 0 ; } else if x % 5 = = 0 { break 0 .. = x ; } x - = 1 ; } }

return (in functions) #[auto_enum] can parse the return in the scope. This analysis is valid only when the return type is impl Trait . use auto_enums :: auto_enum ; #[ auto_enum ( Iterator )] fn func ( x : i32 ) - > impl Iterator < Item = i32 > { if x = = 0 { return Some ( 0 ). into_iter (); } if x > 0 { 0 .. x } else { x .. = 0 } }

return (in closures) #[auto_enum] can parse the return in the scope. This analysis is valid only when the following two conditions are satisfied. #[auto_enum] must be used directly for that closure (or the let binding of the closure). ? operator not used in the scope. use auto_enums :: auto_enum ; #[ auto_enum ] fn closure () - > impl Iterator < Item = i32 > { #[ auto_enum ( Iterator )] let f = | x | { if x = = 0 { return Some ( 0 ). into_iter (); } if x > 0 { 0 .. x } else { x .. = 0 } }; f ( 1 ) }

? operator (in functions) #[auto_enum] can parse the ? operator in the scope. This analysis is valid only when the return type is Result<T, impl Trait> . use auto_enums :: auto_enum ; use std :: fmt ::{ Debug , Display }; #[ auto_enum ( Debug , Display )] fn func ( x : i32 ) - > Result < i32 , impl Debug + Display > { if x = = 0 { Err ( "`x` is zero" ) ? ; } if x < 0 { Err ( x ) ? } else { Ok ( x + 1 ) } } ? operator is expanded as follows: match expr { Ok ( val ) = > val , Err ( err ) = > return Err ( Enum :: Veriant ( err )), }

? operator (in closures) #[auto_enum] can parse the ? operator in the scope. However, #[auto_enum] must be used directly for that closure (or the let binding of the closure). use auto_enums :: auto_enum ; use std :: fmt ::{ Debug , Display }; #[ auto_enum ] fn closure () - > Result < i32 , impl Debug + Display > { #[ auto_enum ( Debug , Display )] let f = | x | { if x = = 0 { Err ( "`x` is zero" ) ? } if x < 0 { Err ( x ) ? } else { Ok ( x + 1 ) } }; f ( 1 ) }

Block, unsafe block, method call, parentheses, and type ascription The following expressions are recursively searched until an if , match , loop or unsupported expression is found. blocks unsafe blocks method calls parentheses type ascriptions use auto_enums :: auto_enum ; #[ auto_enum ] fn expr_block ( x : i32 ) - > impl Iterator < Item = i32 > { #[ auto_enum ( Iterator )] { if x = = 0 { Some ( 0 ). into_iter () } else { 0 .. x } } } #[ auto_enum ] fn expr_method ( x : i32 ) - > impl Iterator < Item = i32 > { #[ auto_enum ( Iterator )] match x { 0 = > Some ( 0 ). into_iter (), _ = > 0 .. x , }. map ( | y | y + 1 ) } #[ auto_enum ( Iterator )] fn expr_parentheses ( x : i32 ) - > impl Iterator < Item = i32 > { ( if x = = 0 { Some ( 0 ). into_iter () } else { 0 .. x }) }



If the last expression of a branch is one of the following, it is interpreted that no value will be returned (variant assignment is skipped).

panic!(..)

unreachable!(..)

return

break

continue

None?

Err(..)?

Expression level marker ( marker! macro).

macro). An item definition.

Also, if the branch contains #[nested] , it is interpreted as returning an anonymous enum generated by #[auto_enum] , not a value.

use auto_enums :: auto_enum ; #[ auto_enum ( Iterator )] fn foo ( x : i32 ) - > impl Iterator < Item = i32 > { match x { 0 = > 1 .. 10 , 1 = > panic ! (), _ = > vec ! [ 5 , 10 ]. into_iter (), } }

You can also skip that branch explicitly by #[never] attribute.

use auto_enums :: auto_enum ; #[ auto_enum ( Iterator )] fn foo ( x : i32 ) - > impl Iterator < Item = i32 > { match x { 0 = > 1 .. 10 , #[ never ] 1 = > loop { panic ! () }, _ = > vec ! [ 5 , 10 ]. into_iter (), } }

#[auto_enum] replaces marker! macros with variants. If values of two or more are specified by marker! macros, #[auto_enum] can be used for unsupported expressions and statements.

use auto_enums :: auto_enum ; #[ auto_enum ( Iterator )] fn foo ( x : i32 ) - > impl Iterator < Item = i32 > { if x < 0 { return x .. = 0 ; } marker ! ( 1 .. 10 ) }

The default name of the macro is "marker" , but you can change it by marker option.

use auto_enums :: auto_enum ; #[ auto_enum ( marker = bar , Iterator )] fn foo ( x : i32 ) - > impl Iterator < Item = i32 > { if x < 0 { return x .. = 0 ; } bar ! ( 1 .. 10 ) }

When using #[auto_enum] for expressions and statements, #[auto_enum] for function is unnecessary.

#![ feature ( proc_macro_hygiene , stmt_expr_attributes )]

use auto_enums :: auto_enum ; fn foo ( x : i32 ) - > i32 { #[ auto_enum ( Iterator )] let iter = match x { 0 = > 1 .. 10 , _ = > vec ! [ 5 , 10 ]. into_iter (), }; iter . fold ( 0 , | sum , x | sum + x ) }

You can also return closures.

#![ feature ( fn_traits , unboxed_closures )]

use auto_enums :: auto_enum ; #[ auto_enum ( Fn )] fn foo ( x : bool ) - > impl Fn ( i32 ) - > i32 { if x { | y | y + 1 } else { | z | z - 1 } }

#[enum_derive] implements the supported traits and passes unsupported traits to #[derive] .

If you want to use traits that are not supported by #[enum_derive] , you can use another crate that provides proc_macro_derive , or you can define proc_macro_derive yourself(derive_utils probably can help it).

Basic usage of #[enum_derive]

use auto_enums :: enum_derive ; #[ enum_derive ( Iterator , Clone )] enum Foo < A , B > { A ( A ), B ( B ), }

#[enum_derive] adds the dependency of the specified trait if it is not specified.

use auto_enums :: enum_derive ; #[ enum_derive ( ExactSizeIterator )] enum Foo < A , B > { A ( A ), B ( B ), }

Some traits support is disabled by default. Note that some traits have aliases.

When using features that depend on unstable APIs, the unstable feature must be explicitly enabled

[std|core]::iter

See also iter-enum crate.

[std|core]::future

See also futures-enum crate.

std::io (requires "std" crate feature)

See also io-enum crate.

[std|core]::ops

Deref (requires "ops" crate feature)

(requires crate feature) DerefMut (requires "ops" crate feature)

(requires crate feature) Index (requires "ops" crate feature)

(requires crate feature) IndexMut (requires "ops" crate feature)

(requires crate feature) RangeBounds (requires "ops" crate feature)

(requires crate feature) Fn (requires "fn_traits" and "unstable" crate features)

(requires and crate features) FnMut (requires "fn_traits" and "unstable" crate features)

(requires and crate features) FnOnce (requires "fn_traits" and "unstable" crate features)

(requires and crate features) Generator (requires "generator_trait" and "unstable" crate features)

[std|core]::convert

AsRef (requires "convert" crate feature)

(requires crate feature) AsMut (requires "convert" crate feature)

[std|core]::fmt

std::error (requires "std" crate feature)

You can add support for external library by activating the each crate feature.

futures(v0.3) (requires "futures03" or "futures" crate feature)

See also futures-enum crate.

futures(v0.1) (requires "futures01" crate feature)

rayon (requires "rayon" crate feature)

serde (requires "serde" crate feature)

tokio(v0.2) (requires "tokio02" crate feature)

tokio(v0.1) (requires "tokio01" crate feature)

These don't derive traits, but derive inherent methods instead.

Transpose (requires "transpose_methods" crate feature) - this derives the following conversion methods. transpose - convert from enum<Option<T1>,..> to Option<enum<T1,..>> transpose - convert from enum<Result<T1, E1>,..> to Result<enum<T1,..>, enum<E1,..>> transpose_ok - convert from enum<Result<T1, E>,..> to Option<enum<T1,..>, E> Examples: use auto_enums :: auto_enum ; use std ::{ fs , io , path :: Path }; #[ auto_enum ( Transpose , Write )] fn output_stream ( file : Option < & Path > ) - > io :: Result < impl io :: Write > { match file { Some ( f ) = > fs :: File :: create ( f ), None = > Ok ( io :: stdout ()), }. transpose_ok () } transpose_err - convert from enum<Result<T, E1>,..> to Result<T, enum<E1,..>>



std Enabled by default. Enable to use std library's traits.

ops Disabled by default. Enable to use [std|core]::ops 's Deref , DerefMut , Index , IndexMut , and RangeBounds traits.

convert Disabled by default. Enable to use [std|core]::convert 's AsRef and AsMut traits.

fmt Disabled by default. Enable to use [std|core]::fmt 's traits other than Debug , Display and Write .

transpose_methods Disabled by default. Enable to use transpose* methods.



Analyze return type of function and let binding.

Note that this feature is still experimental.

Examples:

use auto_enums :: auto_enum ; #[ auto_enum ] fn func ( x : i32 ) - > impl Iterator < Item = i32 > { match x { 0 = > 1 .. 10 , _ = > vec ! [ 5 , 10 ]. into_iter (), } } #[ auto_enum ] fn bar ( x : i32 ) { #[ auto_enum ] let _iter : impl Iterator < Item = i32 > = match x { 0 = > Some ( 0 ). into_iter (), _ = > 0 .. x , }; }

Please be careful if you return another traits with the same name.

futures - futures(v0.3) (requires "unstable" crate feature)

futures01 - futures(v0.1)

rayon - rayon

serde - serde

For these features, you need to enable the unstable feature gate of the same name.

Note that support for these features are unstable and may cause incompatible changes between patch versions.

generator_trait - Enable to use [std|core]::ops::Generator trait.

fn_traits - Enable to use [std|core]::ops 's Fn , FnMut , and FnOnce traits.

trusted_len - Enable to use [std|core]::iter::TrustedLen trait.