fn gen_mock_method(mock_struct_name: &syn::Ident,
                   mod_ident: Option<&syn::Ident>,
                   meth_attrs: &[syn::Attribute],
                   meth_vis: &syn::Visibility,
                   expect_vis: &syn::Visibility,
                   sig: &syn::Signature,
                   sub: Option<&syn::Ident>,
                   generics: &syn::Generics)
    -> (TokenStream, TokenStream, TokenStream)
{
    assert!(sig.variadic.is_none(),
        "MockAll does not yet support variadic functions");
    let mut mock_output = TokenStream::new();
    let mut expect_output = TokenStream::new();
    let mut cp_output = TokenStream::new();
    let constness = sig.constness;
    let unsafety = sig.unsafety;
    let asyncness = sig.asyncness;
    let abi = &sig.abi;
    let fn_token = &sig.fn_token;
    let ident = &sig.ident;
    let meth_types = method_types(sig, Some(generics));
    let merged_g = merge_generics(&generics, &meth_types.expectation_generics);
    let inputs = &meth_types.inputs;
    let output = &meth_types.output;
    let attrs = format_attrs(meth_attrs);

    // First the mock method
    {
        let (ig, _, wc) = sig.generics.split_for_impl();
        quote!(#attrs #meth_vis #constness #unsafety #asyncness #abi
               #fn_token #ident #ig (#inputs) #output #wc)
            .to_tokens(&mut mock_output);
    }

    let expectation = &meth_types.expectation;
    let call = &meth_types.call;
    let call_exprs = &meth_types.call_exprs;
    let mut args = Vec::new();
    let expect_obj_name = if let Some(s) = sub {
        let sub_struct = format_ident!("{}_expectations", s);
        quote!(self.#sub_struct.#ident)
    } else {
        quote!(self.#ident)
    };
    for p in inputs.iter() {
        match p {
            syn::FnArg::Receiver(_) => {
                // Don't output the "self" argument
            },
            syn::FnArg::Typed(arg) => {
                args.push(arg.pat.clone());
            },
        }
    }

    let (ig, _, wc) = meth_types.expectation_generics.split_for_impl();
    let tbf_g = if meth_types.is_static || meth_types.is_expectation_generic {
        // For generic and static methods only, the trait's generic parameters
        // become generic parameters of the method.
        &merged_g
    } else {
        &meth_types.expectation_generics
    }.clone();
    let (tbf_tg, _, _) = split_lifetimes(tbf_g, &inputs, &sig.output);
    let (_, tg, _) = tbf_tg.split_for_impl();
    let call_turbofish = tg.as_turbofish();
    let no_match_msg = format!("{}::{}: No matching expectation found",
        mock_struct_name, ident);
    if meth_types.is_static {
        quote!({
            {
                let __mockall_guard = #mod_ident::#ident::EXPECTATIONS
                    .lock().unwrap();
                /*
                 * TODO: catch panics, then gracefully release the mutex so it
                 * won't be poisoned.  This requires bounding any generic
                 * parameters with UnwindSafe
                 */
                /* std::panic::catch_unwind(|| */
                __mockall_guard.#call#call_turbofish(#call_exprs)
                /*)*/
            }.expect(#no_match_msg)
            /*}.unwrap()*/
        })
    } else {
        quote!({
            #expect_obj_name.#call#call_turbofish(#call_exprs)
            .expect(#no_match_msg)
        })
    }.to_tokens(&mut mock_output);

    // Then the expectation method
    if meth_types.is_static {
        #[cfg(all(not(test),feature = "extra-docs"))]
        let docstr = {
            let inner_ds = format!("Create a [`Context`]({}/{}/struct.Context.html) for mocking the `{}` method",
                quote!(#mod_ident), ident, ident);
            quote!( #[doc = #inner_ds])
        };
        #[cfg(any(test, not(feature = "extra-docs")))]
        let docstr: Option<syn::Attribute> = None;
        let context_ident = format_ident!("{}_context", ident);
        let (_, ctx_tg, _) = generics.split_for_impl();
        quote!(#attrs #docstr #expect_vis fn #context_ident()
               -> #mod_ident::#ident::Context #ctx_tg
            {
                #mod_ident::#ident::Context::default()
            }
        )
    } else {
        #[cfg(all(not(test),feature = "extra-docs"))]
        let docstr = {
            let inner_ds = format!("Create an [`Expectation`]({}/{}/struct.Expectation.html) for mocking the `{}` method",
                quote!(#mod_ident), ident, ident);
            quote!( #[doc = #inner_ds])
        };
        #[cfg(any(test, not(feature = "extra-docs")))]
        let docstr: Option<syn::Attribute> = None;
        let expect_ident = format_ident!("expect_{}", ident);

        #[cfg(not(feature = "nightly_derive"))]
        let must_use = quote!(#[must_use =
                "Must set return value when not using the \"nightly\" feature"
            ]);
        #[cfg(feature = "nightly_derive")]
        let must_use = quote!();

        quote!(
            #must_use
            #attrs #docstr #expect_vis fn #expect_ident #ig(&mut self)
               -> &mut #mod_ident::#expectation
               #wc
            {
                #expect_obj_name.expect#call_turbofish()
            }
        )
    }.to_tokens(&mut expect_output);

    // Finally this method's contribution to the checkpoint method
    if meth_types.is_static {
        // Don't checkpoint static methods.  They get checkpointed by their
        // context objects instead.
        quote!()
    } else {
        quote!(#attrs { #expect_obj_name.checkpoint(); })
    }.to_tokens(&mut cp_output);

    (mock_output, expect_output, cp_output)
}
/// Generate a mock method and its expectation method
///
/// # Arguments
///
/// * `mock_struct_name: Name of the mock structure, not the original one, like
///                     "MockFoo".
/// * `mod_ident`:      Name of the module that contains the expectation! macro,
///                     like __mock_Foo
/// * `meth_attrs`:     Any attributes on the original method, like #[inline]
/// * `meth_vis`:       Visibility of the original method
/// * `expect_vis`:     Desired visiblity of the expect_XXX method
/// * `sig`:            Signature of the original method
/// * `sub`:            Name of the trait containing the method's expectation
///                     object, if any.
/// * `generics`:       Generics of the method's parent trait or structure,
///                     _not_ the method itself.
Generate a mock method and its expectation method
Generate a mock method and its expectation method
fn gen_mock_method(mock_struct_name: &syn::Ident,
                   mod_ident: Option<&syn::Ident>,
                   meth_attrs: &[syn::Attribute],
                   meth_vis: &syn::Visibility,
                   expect_vis: &syn::Visibility,
                   sig: &syn::Signature,
                   sub: Option<&syn::Ident>,
                   generics: &syn::Generics)
    -> (TokenStream, TokenStream, TokenStream)
{
    assert!(sig.variadic.is_none(),
        "MockAll does not yet support variadic functions");
    let mut mock_output = TokenStream::new();
    let mut expect_output = TokenStream::new();
    let mut cp_output = TokenStream::new();
    let constness = sig.constness;
    let unsafety = sig.unsafety;
    let asyncness = sig.asyncness;
    let abi = &sig.abi;
    let fn_token = &sig.fn_token;
    let ident = &sig.ident;
    let meth_types = method_types(sig, Some(generics));
    let merged_g = merge_generics(&generics, &meth_types.expectation_generics);
    let inputs = &meth_types.inputs;
    let output = &meth_types.output;
    let attrs = format_attrs(meth_attrs);
    // First the mock method
    {
        let (ig, _, wc) = sig.generics.split_for_impl();
        quote!(#attrs #meth_vis #constness #unsafety #asyncness #abi
               #fn_token #ident #ig (#inputs) #output #wc)
            .to_tokens(&mut mock_output);
    }
    let expectation = &meth_types.expectation;
    let call = &meth_types.call;
    let call_exprs = &meth_types.call_exprs;
    let mut args = Vec::new();
    let expect_obj_name = if let Some(s) = sub {
        let sub_struct = format_ident!("{}_expectations", s);
        quote!(self.#sub_struct.#ident)
    } else {
        quote!(self.#ident)
    };
    for p in inputs.iter() {
        match p {
            syn::FnArg::Receiver(_) => {
                // Don't output the "self" argument
            },
            syn::FnArg::Typed(arg) => {
                args.push(arg.pat.clone());
            },
        }
    }
    let (ig, _, wc) = meth_types.expectation_generics.split_for_impl();
    let tbf_g = if meth_types.is_static || meth_types.is_expectation_generic {
        // For generic and static methods only, the trait's generic parameters
        // become generic parameters of the method.
        &merged_g
    } else {
        &meth_types.expectation_generics
    }.clone();
    let (tbf_tg, _, _) = split_lifetimes(tbf_g, &inputs, &sig.output);
    let (_, tg, _) = tbf_tg.split_for_impl();
    let call_turbofish = tg.as_turbofish();
    let no_match_msg = format!("{}::{}: No matching expectation found",
        mock_struct_name, ident);
    if meth_types.is_static {
        quote!({
            {
                let __mockall_guard = #mod_ident::#ident::EXPECTATIONS
                    .lock().unwrap();
                /*
                 * TODO: catch panics, then gracefully release the mutex so it
                 * won't be poisoned.  This requires bounding any generic
                 * parameters with UnwindSafe
                 */
                /* std::panic::catch_unwind(|| */
                __mockall_guard.#call#call_turbofish(#call_exprs)
                /*)*/
            }.expect(#no_match_msg)
            /*}.unwrap()*/
        })
    } else {
        quote!({
            #expect_obj_name.#call#call_turbofish(#call_exprs)
            .expect(#no_match_msg)
        })
    }.to_tokens(&mut mock_output);
    // Then the expectation method
    if meth_types.is_static {
        #[cfg(all(not(test),feature = "extra-docs"))]
        let docstr = {
            let inner_ds = format!("Create a [`Context`]({}/{}/struct.Context.html) for mocking the `{}` method",
                quote!(#mod_ident), ident, ident);
            quote!( #[doc = #inner_ds])
        };
        #[cfg(any(test, not(feature = "extra-docs")))]
        let docstr: Option<syn::Attribute> = None;
        let context_ident = format_ident!("{}_context", ident);
        let (_, ctx_tg, _) = generics.split_for_impl();
        quote!(#attrs #docstr #expect_vis fn #context_ident()
               -> #mod_ident::#ident::Context #ctx_tg
            {
                #mod_ident::#ident::Context::default()
            }
        )
    } else {
        #[cfg(all(not(test),feature = "extra-docs"))]
        let docstr = {
            let inner_ds = format!("Create an [`Expectation`]({}/{}/struct.Expectation.html) for mocking the `{}` method",
                quote!(#mod_ident), ident, ident);
            quote!( #[doc = #inner_ds])
        };
        #[cfg(any(test, not(feature = "extra-docs")))]
        let docstr: Option<syn::Attribute> = None;
        let expect_ident = format_ident!("expect_{}", ident);
        #[cfg(not(feature = "nightly_derive"))]
        let must_use = quote!(#[must_use =
                "Must set return value when not using the \"nightly\" feature"
            ]);
        #[cfg(feature = "nightly_derive")]
        let must_use = quote!();
        quote!(
            #must_use
            #attrs #docstr #expect_vis fn #expect_ident #ig(&mut self)
               -> &mut #mod_ident::#expectation
               #wc
            {
                #expect_obj_name.expect#call_turbofish()
            }
        )
    }.to_tokens(&mut expect_output);
    // Finally this method's contribution to the checkpoint method
    if meth_types.is_static {
        // Don't checkpoint static methods.  They get checkpointed by their
        // context objects instead.
        quote!()
    } else {
        quote!(#attrs { #expect_obj_name.checkpoint(); })
    }.to_tokens(&mut cp_output);
    (mock_output, expect_output, cp_output)
}
fn gen_mock_method ( mock_struct_name : & syn :: Ident , mod_ident : Option < & syn :: Ident > , meth_attrs : & [ syn :: Attribute ] , meth_vis : & syn :: Visibility , expect_vis : & syn :: Visibility , sig : & syn :: Signature , sub : Option < & syn :: Ident > , generics : & syn :: Generics ) -> ( TokenStream , TokenStream , TokenStream ) { assert ! ( sig variadic is_none ( ) " " ) ; let mut mock_output = TokenStream :: new ( ) ; let mut expect_output = TokenStream :: new ( ) ; let mut cp_output = TokenStream :: new ( ) ; let constness = sig . constness ; let unsafety = sig . unsafety ; let asyncness = sig . asyncness ; let abi = & sig . abi ; let fn_token = & sig . fn_token ; let ident = & sig . ident ; let meth_types = method_types ( sig , Some ( generics ) ) ; let merged_g = merge_generics ( & generics , & meth_types . expectation_generics ) ; let inputs = & meth_types . inputs ; let output = & meth_types . output ; let attrs = format_attrs ( meth_attrs ) ; // First the mock method { let ( ig , _ , wc ) = sig . generics . split_for_impl ( ) ; quote ! ( attrs meth_vis constness unsafety asyncness abi fn_token ident ig ( inputs ) output wc ) . to_tokens ( & mut mock_output ) ; } let expectation = & meth_types . expectation ; let call = & meth_types . call ; let call_exprs = & meth_types . call_exprs ; let mut args = Vec :: new ( ) ; let expect_obj_name = if let Some ( s ) = sub { let sub_struct = format_ident ! ( " " s ) ; quote ! ( self sub_struct ident ) } else { quote ! ( self ident ) } ; for p in inputs . iter ( ) { match p { syn :: FnArg :: Receiver ( _ ) => { // Don't output the "self" argument } , syn :: FnArg :: Typed ( arg ) => { args . push ( arg . pat . clone ( ) ) ; } , } } let ( ig , _ , wc ) = meth_types . expectation_generics . split_for_impl ( ) ; let tbf_g = if meth_types . is_static || meth_types . is_expectation_generic { // For generic and static methods only, the trait's generic parameters // become generic parameters of the method. & merged_g } else { & meth_types . expectation_generics } . clone ( ) ; let ( tbf_tg , _ , _ ) = split_lifetimes ( tbf_g , & inputs , & sig . output ) ; let ( _ , tg , _ ) = tbf_tg . split_for_impl ( ) ; let call_turbofish = tg . as_turbofish ( ) ; let no_match_msg = format ! ( " " mock_struct_name ident ) ; if meth_types . is_static { quote ! ( { { let __mockall_guard mod_ident ident EXPECTATIONS lock ( ) unwrap ( ) /*
                 * TODO: catch panics, then gracefully release the mutex so it
                 * won't be poisoned.  This requires bounding any generic
                 * parameters with UnwindSafe
                 */ /* std::panic::catch_unwind(|| */ __mockall_guard call call_turbofish ( call_exprs ) /*)*/ } expect ( no_match_msg ) /*}.unwrap()*/ } ) } else { quote ! ( { expect_obj_name call call_turbofish ( call_exprs ) expect ( no_match_msg ) } ) } . to_tokens ( & mut mock_output ) ; // Then the expectation method if meth_types . is_static { # [ cfg ( all ( not ( test ) feature " " ) ) ] let docstr = { let inner_ds = format ! ( " " quote ( mod_ident ) ident ident ) ; quote ! ( [ doc inner_ds ] ) } ; # [ cfg ( any ( test not ( feature " " ) ) ) ] let docstr : Option < syn :: Attribute > = None ; let context_ident = format_ident ! ( " " ident ) ; let ( _ , ctx_tg , _ ) = generics . split_for_impl ( ) ; quote ! ( attrs docstr expect_vis fn context_ident ( ) mod_ident ident Context ctx_tg { mod_ident ident Context default ( ) } ) } else { # [ cfg ( all ( not ( test ) feature " " ) ) ] let docstr = { let inner_ds = format ! ( " " quote ( mod_ident ) ident ident ) ; quote ! ( [ doc inner_ds ] ) } ; # [ cfg ( any ( test not ( feature " " ) ) ) ] let docstr : Option < syn :: Attribute > = None ; let expect_ident = format_ident ! ( " " ident ) ; # [ cfg ( not ( feature " " ) ) ] let must_use = quote ! ( [ must_use " \" \" " ] ) ; # [ cfg ( feature " " ) ] let must_use = quote ! ( ) ; quote ! ( must_use attrs docstr expect_vis fn expect_ident ig ( mut self ) mut mod_ident expectation wc { expect_obj_name expect call_turbofish ( ) } ) } . to_tokens ( & mut expect_output ) ; // Finally this method's contribution to the checkpoint method if meth_types . is_static { // Don't checkpoint static methods.  They get checkpointed by their // context objects instead. quote ! ( ) } else { quote ! ( attrs { expect_obj_name checkpoint ( ) } ) } . to_tokens ( & mut cp_output ) ; ( mock_output , expect_output , cp_output ) }
Generate a mock method and its expectation method
Generate a mock method and its expectation method
mock_struct_name
&syn::Ident
mod_ident
Option<&syn::Ident>
meth_attrs
&[syn::Attribute]
meth_vis
&syn::Visibility
expect_vis
&syn::Visibility
sig
&syn::Signature
sub
Option<&syn::Ident>
generics
&syn::Generics
mock_struct_name
&syn::Ident
mod_ident
Option<&syn::Ident>
meth_attrs
&[syn::Attribute]
meth_vis
&syn::Visibility
expect_vis
&syn::Visibility
sig
&syn::Signature
sub
Option<&syn::Ident>
generics
&syn::Generics