/// Extract useful data about a method
///
/// # Arguments
///
/// * `sig`:            Signature of the original method
/// * `generics`:       Generics of the method's parent trait or structure,
///                     _not_ the method itself.
Extract useful data about a method
Extract useful data about a method
fn method_types(sig: &Signature, generics: Option<&Generics>) -> MethodTypes {
    let mut is_static = true;
    let ident = &sig.ident;
    let (expectation_generics, expectation_inputs, call_exprs) =
        declosurefy(&sig.generics, &sig.inputs);
    let merged_generics = if let Some(g) = generics {
        merge_generics(&g, &expectation_generics)
    } else {
        sig.generics.clone()
    };
    let inputs = demutify(&sig.inputs);
    let (no_lt_g, _, rlg) = split_lifetimes(merged_generics.clone(),
                                            &sig.inputs, &sig.output);
    let with_ret_lt_g = merge_generics(&no_lt_g, &rlg);
    for fn_arg in expectation_inputs.iter() {
        match fn_arg {
            FnArg::Typed(_) => {},
            FnArg::Receiver(_) => {
                is_static = false;
            },
        }
    }
    let call = match &sig.output {
        ReturnType::Default => {
            format_ident!("call")
        },
        ReturnType::Type(_, ty) => {
            match ty.as_ref() {
                Type::Reference(r) => {
                    if let Some(ref lt) = r.lifetime {
                        if lt.ident != "static" {
                            compile_error(r.span(), "Non-'static non-'self lifetimes are not yet supported");
                        }
                    }
                    if r.mutability.is_some() {
                        format_ident!("call_mut")
                    } else {
                        format_ident!("call")
                    }
                },
                _ => format_ident!("call")
            }
        }
    };
    let is_expectation_generic = expectation_generics.params.iter()
        .any(|p| {
            if let GenericParam::Type(_) = p {
                true
            } else {
                false
            }
        }) ||
        expectation_generics.where_clause.is_some() ||
        (is_static && generics.filter(|g| !g.params.is_empty()).is_some());
    let expectation_ident = format_ident!("Expectation");
    let expectations_ident = if is_expectation_generic {
        format_ident!("GenericExpectations")
    } else {
        format_ident!("Expectations")
    };
    let expectations = parse2(
        quote!(#ident::#expectations_ident)
    ).unwrap();
    // Replace any generic lifetimes of the Expectation's type with 'static
    // TODO: in the future, only replace those lifetimes that _don't_ appear
    // in the original trait's or struct's signature.
    let expectation_g = staticize(&with_ret_lt_g);
    let (_, expectation_tg, _) = expectation_g.split_for_impl();
    let expect_ts = quote!(#ident::#expectation_ident #expectation_tg);
    let expect_obj = if is_expectation_generic {
        parse2(quote!(#expectations))
    } else {
        parse2(quote!(#expectations #expectation_tg))
    }.unwrap();
    let expectation: Type = parse2(expect_ts).unwrap();
    let mut output = sig.output.clone();
    deimplify(&mut output);
    MethodTypes{is_static, is_expectation_generic, expectation,
                expectation_generics, expectation_inputs, expectations, call,
                expect_obj, call_exprs, inputs, output}
}
fn method_types ( sig : & Signature , generics : Option < & Generics > ) -> MethodTypes { let mut is_static = true ; let ident = & sig . ident ; let ( expectation_generics , expectation_inputs , call_exprs ) = declosurefy ( & sig . generics , & sig . inputs ) ; let merged_generics = if let Some ( g ) = generics { merge_generics ( & g , & expectation_generics ) } else { sig . generics . clone ( ) } ; let inputs = demutify ( & sig . inputs ) ; let ( no_lt_g , _ , rlg ) = split_lifetimes ( merged_generics . clone ( ) , & sig . inputs , & sig . output ) ; let with_ret_lt_g = merge_generics ( & no_lt_g , & rlg ) ; for fn_arg in expectation_inputs . iter ( ) { match fn_arg { FnArg :: Typed ( _ ) => { } , FnArg :: Receiver ( _ ) => { is_static = false ; } , } } let call = match & sig . output { ReturnType :: Default => { format_ident ! ( " " ) } , ReturnType :: Type ( _ , ty ) => { match ty . as_ref ( ) { Type :: Reference ( r ) => { if let Some ( ref lt ) = r . lifetime { if lt . ident != " " { compile_error ( r . span ( ) , " " ) ; } } if r . mutability . is_some ( ) { format_ident ! ( " " ) } else { format_ident ! ( " " ) } } , _ => format_ident ! ( " " ) } } } ; let is_expectation_generic = expectation_generics . params . iter ( ) . any ( | p | { if let GenericParam :: Type ( _ ) = p { true } else { false } } ) || expectation_generics . where_clause . is_some ( ) || ( is_static && generics . filter ( | g | ! g . params . is_empty ( ) ) . is_some ( ) ) ; let expectation_ident = format_ident ! ( " " ) ; let expectations_ident = if is_expectation_generic { format_ident ! ( " " ) } else { format_ident ! ( " " ) } ; let expectations = parse2 ( quote ! ( ident expectations_ident ) ) . unwrap ( ) ; // Replace any generic lifetimes of the Expectation's type with 'static // TODO: in the future, only replace those lifetimes that _don't_ appear // in the original trait's or struct's signature. let expectation_g = staticize ( & with_ret_lt_g ) ; let ( _ , expectation_tg , _ ) = expectation_g . split_for_impl ( ) ; let expect_ts = quote ! ( ident expectation_ident expectation_tg ) ; let expect_obj = if is_expectation_generic { parse2 ( quote ! ( expectations ) ) } else { parse2 ( quote ! ( expectations expectation_tg ) ) } . unwrap ( ) ; let expectation : Type = parse2 ( expect_ts ) . unwrap ( ) ; let mut output = sig . output . clone ( ) ; deimplify ( & mut output ) ; MethodTypes { is_static , is_expectation_generic , expectation , expectation_generics , expectation_inputs , expectations , call , expect_obj , call_exprs , inputs , output } }
Extract useful data about a method
Extract useful data about a method
sig
&Signature
generics
Option<&Generics>