fn check_decl( decl: &syn::Signature ) -> TestKind {
    assert!( decl.generics.lifetimes().next().is_none(), "Lifetimes are yet not supported" );
    assert!( decl.generics.where_clause.is_none(), "`where` clauses are not supported" );
    assert!( decl.variadic.is_none(), "Variadic functions are not supported" );

    if !check_return_type( &decl.output ) {
        panic!( "The function should not return anything!" );
    }

    let mut type_params: Vec< _ > = decl.generics.type_params().collect();
    if type_params.is_empty() && decl.inputs.is_empty() {
        // Exactly like a normal #[test].
        //   fn test_foo() {}
        return TestKind::Synchronous;
    }

    assert_eq!( type_params.len(), 1, "The function should have a single type parameter" );

    let type_param = type_params.pop().unwrap();
    assert!( type_param.attrs.is_empty(), "Type param attributes are not supported" );
    assert!( type_param.default.is_none(), "Type param defaults are not supported" );
    assert!( type_param.eq_token.is_none() );
    assert_eq!( type_param.bounds.len(), 1, "The type param should have only one bound" );
    let bound = match type_param.bounds[ 0 ].clone() {
        syn::TypeParamBound::Lifetime( .. ) => panic!( "Lifetime type param bounds are not supported" ),
        syn::TypeParamBound::Trait( bound ) => bound
    };
    match bound.modifier {
        syn::TraitBoundModifier::None => {},
        syn::TraitBoundModifier::Maybe( _ ) => panic!( "'?Trait' type bounds are not supported" )
    }
    assert!( bound.lifetimes.is_none(), "Lifetimes in type param bounds are not supported" );

    if !bound.path.leading_colon.is_none() ||
        bound.path.segments.len() != 1 ||
        bound.path.segments[ 0 ].ident != "FnOnce"
    {
        panic!( "Unsupported type bound" );
    }

    enum Kind {
        Simple,
        Fallible {
            result_ty: syn::Type
        }
    }

    let kind: Kind = match bound.path.segments[ 0 ].arguments {
        syn::PathArguments::Parenthesized( syn::ParenthesizedGenericArguments { ref inputs, ref output, .. } ) => {
            match output {
                syn::ReturnType::Default => {},
                _ => panic!( "Unsupported type bound" )
            }

            let inputs: Vec< _ > = inputs.iter().collect();
            match *inputs {
                [] => {
                    // A test which can only succeed, or timeout.
                    //  fn test_foo< F: FnOnce() >( cb: F ) {}
                    Kind::Simple
                },
                [
                    syn::Type::Path(
                        syn::TypePath {
                            qself: None,
                            path: syn::Path {
                                leading_colon: None,
                                segments
                            }
                        }
                    )
                ] if segments.len() == 1 => {
                    let segment = &segments[ 0 ];
                    if segment.ident != "Result" {
                        panic!( "Unsupported type bound" );
                    }

                    match segment.arguments {
                        syn::PathArguments::AngleBracketed( ref args ) => {
                            if args.args.len() != 2 {
                                panic!( "Unsupported type bound" );
                            }
                            match args.args[ 0 ] {
                                syn::GenericArgument::Type(
                                    syn::Type::Tuple( syn::TypeTuple { ref elems, .. } )
                                ) if elems.is_empty() => {
                                    // A test which can suceed, fail or timeout.
                                    //  fn test_foo< F: FnOnce( Result< (), E > ) >( cb: F ) {}
                                    Kind::Fallible {
                                        result_ty: inputs[ 0 ].clone()
                                    }
                                },
                                _ => panic!( "Unsupported type bound" )
                            }
                        },
                        _ => panic!( "Unsupported type bound" )
                    }
                },
                _ => panic!( "Unsupported type bound" )
            }
        },
        _ => panic!( "Unsupported type bound" )
    };

    if decl.inputs.len() != 1 {
        panic!( "Expected a function with a single argument!" );
    }

    let arg = decl.inputs.last().unwrap();
    match *arg {
        syn::FnArg::Receiver( .. ) => panic!( "`self` is not supported" ),
        syn::FnArg::Typed( syn::PatType { ref pat, ref ty, .. } ) => {
            match **pat {
                syn::Pat::Ident( ref pat ) => {
                    assert!( pat.by_ref.is_none(), "`ref` bindings are not supported" );
                    assert!( pat.mutability.is_none(), "`mut` bindings are not supported" );
                    assert!( pat.subpat.is_none(), "Subpatterns are not supported" );

                    match **ty {
                        syn::Type::Path(
                            syn::TypePath {
                                qself: None,
                                path: syn::Path {
                                    leading_colon: None,
                                    ref segments
                                }
                            }
                        ) if segments.len() == 1 => {
                            if type_param.ident != segments[ 0 ].ident {
                                panic!( "Unsupported argument type" );
                            }
                        },
                        _ => panic!( "Unsupported argument type" )
                    }

                    let callback_ident = pat.ident.clone();
                    match kind {
                        Kind::Simple => TestKind::Simple { callback_ident },
                        Kind::Fallible { result_ty } => TestKind::Fallible {
                            callback_ident,
                            result_ty
                        }
                    }
                },
                _ => panic!( "Argument patterns are not supported" )
            }
        }
    }
}
// TODO: There must be a cleaner way to do this.
There must be a cleaner way to do this.
There must be a cleaner way to do this .
fn check_decl( decl: &syn::Signature ) -> TestKind {
    assert!( decl.generics.lifetimes().next().is_none(), "Lifetimes are yet not supported" );
    assert!( decl.generics.where_clause.is_none(), "`where` clauses are not supported" );
    assert!( decl.variadic.is_none(), "Variadic functions are not supported" );
    if !check_return_type( &decl.output ) {
        panic!( "The function should not return anything!" );
    }
    let mut type_params: Vec< _ > = decl.generics.type_params().collect();
    if type_params.is_empty() && decl.inputs.is_empty() {
        // Exactly like a normal #[test].
        //   fn test_foo() {}
        return TestKind::Synchronous;
    }
    assert_eq!( type_params.len(), 1, "The function should have a single type parameter" );
    let type_param = type_params.pop().unwrap();
    assert!( type_param.attrs.is_empty(), "Type param attributes are not supported" );
    assert!( type_param.default.is_none(), "Type param defaults are not supported" );
    assert!( type_param.eq_token.is_none() );
    assert_eq!( type_param.bounds.len(), 1, "The type param should have only one bound" );
    let bound = match type_param.bounds[ 0 ].clone() {
        syn::TypeParamBound::Lifetime( .. ) => panic!( "Lifetime type param bounds are not supported" ),
        syn::TypeParamBound::Trait( bound ) => bound
    };
    match bound.modifier {
        syn::TraitBoundModifier::None => {},
        syn::TraitBoundModifier::Maybe( _ ) => panic!( "'?Trait' type bounds are not supported" )
    }
    assert!( bound.lifetimes.is_none(), "Lifetimes in type param bounds are not supported" );
    if !bound.path.leading_colon.is_none() ||
        bound.path.segments.len() != 1 ||
        bound.path.segments[ 0 ].ident != "FnOnce"
    {
        panic!( "Unsupported type bound" );
    }
    enum Kind {
        Simple,
        Fallible {
            result_ty: syn::Type
        }
    }
    let kind: Kind = match bound.path.segments[ 0 ].arguments {
        syn::PathArguments::Parenthesized( syn::ParenthesizedGenericArguments { ref inputs, ref output, .. } ) => {
            match output {
                syn::ReturnType::Default => {},
                _ => panic!( "Unsupported type bound" )
            }
            let inputs: Vec< _ > = inputs.iter().collect();
            match *inputs {
                [] => {
                    // A test which can only succeed, or timeout.
                    //  fn test_foo< F: FnOnce() >( cb: F ) {}
                    Kind::Simple
                },
                [
                    syn::Type::Path(
                        syn::TypePath {
                            qself: None,
                            path: syn::Path {
                                leading_colon: None,
                                segments
                            }
                        }
                    )
                ] if segments.len() == 1 => {
                    let segment = &segments[ 0 ];
                    if segment.ident != "Result" {
                        panic!( "Unsupported type bound" );
                    }
                    match segment.arguments {
                        syn::PathArguments::AngleBracketed( ref args ) => {
                            if args.args.len() != 2 {
                                panic!( "Unsupported type bound" );
                            }
                            match args.args[ 0 ] {
                                syn::GenericArgument::Type(
                                    syn::Type::Tuple( syn::TypeTuple { ref elems, .. } )
                                ) if elems.is_empty() => {
                                    // A test which can suceed, fail or timeout.
                                    //  fn test_foo< F: FnOnce( Result< (), E > ) >( cb: F ) {}
                                    Kind::Fallible {
                                        result_ty: inputs[ 0 ].clone()
                                    }
                                },
                                _ => panic!( "Unsupported type bound" )
                            }
                        },
                        _ => panic!( "Unsupported type bound" )
                    }
                },
                _ => panic!( "Unsupported type bound" )
            }
        },
        _ => panic!( "Unsupported type bound" )
    };
    if decl.inputs.len() != 1 {
        panic!( "Expected a function with a single argument!" );
    }
    let arg = decl.inputs.last().unwrap();
    match *arg {
        syn::FnArg::Receiver( .. ) => panic!( "`self` is not supported" ),
        syn::FnArg::Typed( syn::PatType { ref pat, ref ty, .. } ) => {
            match **pat {
                syn::Pat::Ident( ref pat ) => {
                    assert!( pat.by_ref.is_none(), "`ref` bindings are not supported" );
                    assert!( pat.mutability.is_none(), "`mut` bindings are not supported" );
                    assert!( pat.subpat.is_none(), "Subpatterns are not supported" );
                    match **ty {
                        syn::Type::Path(
                            syn::TypePath {
                                qself: None,
                                path: syn::Path {
                                    leading_colon: None,
                                    ref segments
                                }
                            }
                        ) if segments.len() == 1 => {
                            if type_param.ident != segments[ 0 ].ident {
                                panic!( "Unsupported argument type" );
                            }
                        },
                        _ => panic!( "Unsupported argument type" )
                    }
                    let callback_ident = pat.ident.clone();
                    match kind {
                        Kind::Simple => TestKind::Simple { callback_ident },
                        Kind::Fallible { result_ty } => TestKind::Fallible {
                            callback_ident,
                            result_ty
                        }
                    }
                },
                _ => panic!( "Argument patterns are not supported" )
            }
        }
    }
}
fn check_decl ( decl : & syn :: Signature ) -> TestKind { assert ! ( decl generics lifetimes ( ) next ( ) is_none ( ) " " ) ; assert ! ( decl generics where_clause is_none ( ) " " ) ; assert ! ( decl variadic is_none ( ) " " ) ; if ! check_return_type ( & decl . output ) { panic ! ( " " ) ; } let mut type_params : Vec < _ > = decl . generics . type_params ( ) . collect ( ) ; if type_params . is_empty ( ) && decl . inputs . is_empty ( ) { // Exactly like a normal #[test]. //   fn test_foo() {} return TestKind :: Synchronous ; } assert_eq ! ( type_params len ( ) 1 " " ) ; let type_param = type_params . pop ( ) . unwrap ( ) ; assert ! ( type_param attrs is_empty ( ) " " ) ; assert ! ( type_param default is_none ( ) " " ) ; assert ! ( type_param eq_token is_none ( ) ) ; assert_eq ! ( type_param bounds len ( ) 1 " " ) ; let bound = match type_param . bounds [ 0 ] . clone ( ) { syn :: TypeParamBound :: Lifetime ( .. ) => panic ! ( " " ) , syn :: TypeParamBound :: Trait ( bound ) => bound } ; match bound . modifier { syn :: TraitBoundModifier :: None => { } , syn :: TraitBoundModifier :: Maybe ( _ ) => panic ! ( " " ) } assert ! ( bound lifetimes is_none ( ) " " ) ; if ! bound . path . leading_colon . is_none ( ) || bound . path . segments . len ( ) != 1 || bound . path . segments [ 0 ] . ident != " " { panic ! ( " " ) ; } enum Kind { Simple , Fallible { result_ty : syn :: Type } } let kind : Kind = match bound . path . segments [ 0 ] . arguments { syn :: PathArguments :: Parenthesized ( syn :: ParenthesizedGenericArguments { ref inputs , ref output , .. } ) => { match output { syn :: ReturnType :: Default => { } , _ => panic ! ( " " ) } let inputs : Vec < _ > = inputs . iter ( ) . collect ( ) ; match * inputs { [ ] => { // A test which can only succeed, or timeout. //  fn test_foo< F: FnOnce() >( cb: F ) {} Kind :: Simple } , [ syn :: Type :: Path ( syn :: TypePath { qself : None , path : syn :: Path { leading_colon : None , segments } } ) ] if segments . len ( ) == 1 => { let segment = & segments [ 0 ] ; if segment . ident != " " { panic ! ( " " ) ; } match segment . arguments { syn :: PathArguments :: AngleBracketed ( ref args ) => { if args . args . len ( ) != 2 { panic ! ( " " ) ; } match args . args [ 0 ] { syn :: GenericArgument :: Type ( syn :: Type :: Tuple ( syn :: TypeTuple { ref elems , .. } ) ) if elems . is_empty ( ) => { // A test which can suceed, fail or timeout. //  fn test_foo< F: FnOnce( Result< (), E > ) >( cb: F ) {} Kind :: Fallible { result_ty : inputs [ 0 ] . clone ( ) } } , _ => panic ! ( " " ) } } , _ => panic ! ( " " ) } } , _ => panic ! ( " " ) } } , _ => panic ! ( " " ) } ; if decl . inputs . len ( ) != 1 { panic ! ( " " ) ; } let arg = decl . inputs . last ( ) . unwrap ( ) ; match * arg { syn :: FnArg :: Receiver ( .. ) => panic ! ( " " ) , syn :: FnArg :: Typed ( syn :: PatType { ref pat , ref ty , .. } ) => { match * * pat { syn :: Pat :: Ident ( ref pat ) => { assert ! ( pat by_ref is_none ( ) " " ) ; assert ! ( pat mutability is_none ( ) " " ) ; assert ! ( pat subpat is_none ( ) " " ) ; match * * ty { syn :: Type :: Path ( syn :: TypePath { qself : None , path : syn :: Path { leading_colon : None , ref segments } } ) if segments . len ( ) == 1 => { if type_param . ident != segments [ 0 ] . ident { panic ! ( " " ) ; } } , _ => panic ! ( " " ) } let callback_ident = pat . ident . clone ( ) ; match kind { Kind :: Simple => TestKind :: Simple { callback_ident } , Kind :: Fallible { result_ty } => TestKind :: Fallible { callback_ident , result_ty } } } , _ => panic ! ( " " ) } } } }
TODO: There must be a cleaner way to do this.
TODO : There must be a cleaner way to do this .
decl
&syn::Signature
decl
&syn::Signature