enumx 0.4.3

Ad-hoc enum extension.
Documentation
#![cfg_attr( feature = "unstable", feature(
    fn_traits,
    generator_trait,
    generators,
    proc_macro_hygiene,
    stmt_expr_attributes,
    trusted_len,
    unboxed_closures,
))]

use enumx::export::*;

def_impls! {
    #[derive( Exchange )]
    enum Enum![1..=3];
}

#[test]
fn syntax() {
    fn _foo( i: i32 ) -> Enum!( String, &'static str ) {
        if i >= 0 { String::from("positive").exchange_into() } else { "negative".exchange_into() }
    }

    #[enumx] fn _bar( i: i32 ) -> Enum!( String, usize, &'static str ) {
        #[ty_pat] match _foo(i) {
            String(s) => if s.len() % 2 == 0 {
                s.len().exchange_into()
            } else {
                s.exchange_into()
            },
            TyPat::<&'static str>(s) => s.exchange_into(),
        }
    }

    #[enumx] fn _bar_v2( i: i32 ) -> Enum!( String, usize, &'static str ) {
        #[ty_pat(gen_variants)] match _foo(i) {
            String(s) => if s.len() % 2 == 0 {
                s.len().exchange_into()
            } else {
                s.exchange_into()
            },
        }
    }

    #[enumx] fn _bar_v3( i: i32 ) -> Enum!( String, usize, &'static str ) {
        #[ty_pat(gen &'static str)] match _foo(i) {
            String(s) => if s.len() % 2 == 0 {
                s.len().exchange_into()
            } else {
                s.exchange_into()
            },
        }
    }

    #[enumx] fn _baz( i: i32 ) -> Enum!( String, &'static str ) {
        #[ty_pat(gen_variants)] match _bar(i) {
            usize(v) => v.to_string().exchange_into(),
        }
    }

    #[cfg( feature = "unstable" )]
    let _bar = #[enumx] |i: i32| -> Enum!( String, usize, &'static str ) {
        #[ty_pat] match _foo(i) {
            String(s) => if s.len() % 2 == 0 {
                s.len().into_enum()
            } else {
                s.into_enum()
            },
            TyPat::<&'static str>(s) => s.into_enum(),
        }
    };

    #[cfg( feature = "unstable" )]
    #[enumx] let _bar_v2 = |i: i32| -> Enum!( String, usize, &'static str ) {
        #[ty_pat(gen_variants)] match _foo(i) {
            String(s) => if s.len() % 2 == 0 {
                s.len().into_enum()
            } else {
                s.into_enum()
            },
        }
    };
}

#[test]
fn sum_syntax() {
    #[sum] fn _if( cond: bool ) -> impl Clone {
        if cond {
            #[variant] 1_i32
        } else {
            #[variant] 0_u32
        }
    }

    #[cfg( feature = "unstable" )]
    #[sum]
    fn _fn( cond: bool ) -> impl Fn()->i32 {
        if cond {
            #[variant] || 1
        } else {
            #[variant] || 0
        }
    }

    struct ESI0;
    impl Iterator for ESI0 {
        type Item = ();
        fn next( &mut self ) -> Option<()> { None }
        fn size_hint( &self ) -> (usize, Option<usize>) { (0,Some(0)) }
    }
    impl ExactSizeIterator for ESI0 {}

    struct ESI1;
    impl Iterator for ESI1 {
        type Item = ();
        fn next( &mut self ) -> Option<()> { None }
        fn size_hint( &self ) -> (usize, Option<usize>) { (0,Some(0)) }
    }
    impl ExactSizeIterator for ESI1 {}

    #[sum] fn _exact_size_iterator( cond: bool ) -> impl ExactSizeIterator {
        if cond {
            #[variant] ESI0
        } else {
            #[variant] ESI1
        }
    }

    #[sum( ok  => impl Clone )]
    #[sum( err => impl Clone )]
    fn _sum_okeys_and_errors( branch: i32 ) -> Result<impl Clone, impl Clone> {
        match branch % 4 {
            0 => Ok(  #[variant( ok  => _ )] branch ),
            1 => Ok(  #[variant( ok  => _ )] () ),
            2 => Err( #[variant( err => _ )] branch ),
            3 => Err( #[variant( err => _ )] () ),
            _ => unreachable!(),
        }
    }

    #[sum_err]
    #[sum( impl Clone )]
    fn _sum_err( branch: i32 ) -> Result<(), impl Clone> {
        match branch % 3 {
            0 => Ok(()),
            1 => Ok( Err( 0 )? ),
            2 => Ok( Err( "lorum" )? ),
            _ => unreachable!(),
        }
    }
}

#[test]
fn impl_for_predefined() {
    impl_trait!{ _impl!(T) AsRef<T> _for!( Enum![1..=3] )}
    impl_trait!{ _impl!(T) AsMut<T> _for!( Enum![1..=3] )}
    impl_trait!{ DoubleEndedIterator _for!( Enum![1..=3] )}
    impl_trait!{ ExactSizeIterator _for!( Enum![1..=3] )}
    impl_trait!{ _impl!(A) Extend<A> _for!( Enum![1..=3] )}

    #[cfg( feature = "unstable" )]
    impl_trait!{ _impl!(Args) Fn<Args> _for!( Enum![1..=3] )}

    impl_trait!{ Iterator _for!( Enum![1..=3] )}
    impl_trait!{ std::error::Error _for!( Enum![1..=3] )}
    impl_trait!{ std::fmt::Debug _for!( Enum![1..=3] )}
    impl_trait!{ std::fmt::Display _for!( Enum![1..=3] )}
    impl_trait!{ std::iter::FusedIterator _for!( Enum![1..=3] )}

    #[cfg( feature = "unstable" )]
    impl_trait!{ std::iter::TrustedLen _for!( Enum![1..=3] )}

    impl_trait!{ std::io::BufRead _for!( Enum![1..=3] )}
    impl_trait!{ std::io::Read _for!( Enum![1..=3] )}
    impl_trait!{ std::io::Seek _for!( Enum![1..=3] )}
    impl_trait!{ std::io::Write _for!( Enum![1..=3] )}
    impl_trait!{ std::ops::Deref _for!( Enum![1..=3] )}
    impl_trait!{ std::ops::DerefMut _for!( Enum![1..=3] )}

    #[cfg( feature = "unstable" )]
    impl_trait!{ _impl!(R) std::ops::Generator<R> _for!( Enum![1..=3] )}

    impl_trait!{ _impl!(Idx) std::ops::Index<Idx> _for!( Enum![1..=3] )}
    impl_trait!{ _impl!(Idx) std::ops::IndexMut<Idx> _for!( Enum![1..=3] )}
    impl_trait!{ _impl!(T) std::ops::RangeBounds<T> _for!( Enum![1..=3] )}
}

#[test]
#[allow( dead_code )]
fn single_impl() {
    enum Value {
        Code( i32 ),
        Text( String ),
    }
    impl_trait! { std::fmt::Debug _for!(
        _def!{ enum Value {
            Code( i32 ),
            Text( String ),
        }}
    )}
}

#[test]
#[allow( dead_code )]
fn single_impl_with_generics() {
    enum Value<Other> {
        Code( i32 ),
        Text( &'static str ),
        Other( Other ),
    }
    impl_trait! {
        _impl!(Other) std::fmt::Debug _for!(
            _def!{ enum Value<Other> {
                Code( i32 ),
                Text( &'static str ),
                Other( Other ),
            }}
        )
    }
}

#[test]
#[allow( dead_code )]
fn impl_trait_for_def() {
    enum Value<Other> {
        Code( i32 ),
        Text( &'static str ),
        Other( Other ),
    }
    impl_trait! {
        _impl!(Other) std::fmt::Debug _for!(
            _def!{ enum Value<Other> {
                Code( i32 ),
                Text( &'static str ),
                Other( Other ),
            }}
        )
    }
}