From 397ab6e945f3da914abfafd5a1ae7541b01a5c7b Mon Sep 17 00:00:00 2001 From: Audun Halland Date: Sun, 10 Mar 2024 19:25:42 +0100 Subject: [PATCH] Use new responder types --- src/assemble.rs | 2 +- src/build.rs | 106 ++-- src/call_pattern.rs | 108 ++-- src/cell.rs | 2 +- src/eval.rs | 104 ++-- src/lib.rs | 86 ++-- src/mock/std.rs | 5 +- src/output.rs | 728 +++------------------------ src/output_old.rs | 712 ++++++++++++++++++++++++++ src/private.rs | 37 +- src/respond.rs | 521 +++++++++++-------- src/response.rs | 85 ---- tests/it/mixed.rs | 8 +- tests/it/output_generic.rs | 11 +- unimock_macros/src/unimock/mod.rs | 10 +- unimock_macros/src/unimock/output.rs | 218 +++----- 16 files changed, 1439 insertions(+), 1304 deletions(-) create mode 100644 src/output_old.rs delete mode 100644 src/response.rs diff --git a/src/assemble.rs b/src/assemble.rs index 0b1b2b4..6bea0f8 100644 --- a/src/assemble.rs +++ b/src/assemble.rs @@ -2,7 +2,7 @@ use crate::alloc::{format, vec, BTreeMap, Entry, String, ToString}; use crate::build::dyn_builder::DynCallPatternBuilder; use crate::call_pattern::CallPattern; use crate::fn_mocker::{FnMocker, PatternMatchMode}; -use crate::output::ResponderError; +use crate::respond::ResponderError; use crate::Clause; use crate::{clause, MockFnInfo}; diff --git a/src/build.rs b/src/build.rs index 2ed722d..1422194 100644 --- a/src/build.rs +++ b/src/build.rs @@ -3,14 +3,13 @@ use core::marker::PhantomData; use crate::alloc::vec; use crate::call_pattern::*; use crate::fn_mocker::PatternMatchMode; -use crate::output::{IntoCloneResponder, IntoOnceResponder}; use crate::property::*; use crate::*; pub(crate) mod dyn_builder { use crate::alloc::{vec, Vec}; - use crate::output::ResponderError; - use crate::Responder; + use crate::respond::{OutputResponder, ResponderError}; + use crate::MockFn; use crate::{ call_pattern::{DynCallOrderResponder, DynInputMatcher, DynResponder}, @@ -73,9 +72,24 @@ pub(crate) mod dyn_builder { } } - pub fn push_responder_result(&mut self, result: Result) { + // pub fn push_responder_result(&mut self, result: Result) { + // match result { + // Ok(responder) => self.push_responder(responder.0), + // Err(error) => { + // let dyn_builder = self.inner_mut(); + // if dyn_builder.responder_error.is_none() { + // dyn_builder.responder_error = Some(error); + // } + // } + // } + // } + + pub fn push_output_responder_result( + &mut self, + result: Result, ResponderError>, + ) { match result { - Ok(responder) => self.push_responder(responder.0), + Ok(responder) => self.push_responder(responder.into_dyn_responder()), Err(error) => { let dyn_builder = self.inner_mut(); if dyn_builder.responder_error.is_none() { @@ -111,6 +125,7 @@ pub(crate) mod dyn_builder { } use crate::alloc::{String, ToString, Vec}; +use crate::respond::{IntoMultiResponse, IntoOutputResponder, IntoResponse, Respond}; use dyn_builder::*; /// Builder for defining a series of cascading call patterns on a specific [MockFn]. @@ -178,7 +193,7 @@ pub struct DefineResponse<'p, F: MockFn, O: Ordering> { impl<'p, F: MockFn, O: Ordering> DefineResponse<'p, F, O> where - ::Type: Send + Sync, + ::Type: Send + Sync, { /// Specify the output of the call pattern by providing a value. /// The output type cannot contain non-static references. @@ -189,7 +204,8 @@ where /// To be able to return this value multiple times, quantify it explicitly. pub fn returns(self, value: T) -> QuantifyReturnValue<'p, F, T, O> where - T: IntoOnceResponder, + T: IntoResponse, + <::Respond as Respond>::Get: IntoOutputResponder, { QuantifyReturnValue { wrapper: self.wrapper, @@ -215,9 +231,15 @@ where /// Specify the output of the call pattern by providing a value. /// The output type cannot contain non-static references. /// It must also be [Send] and [Sync] because unimock needs to store it, and [Clone] because it should be able to be returned multiple times. - pub fn returns>(mut self, value: V) -> Quantify<'p, F, O> { - self.wrapper - .push_responder_result(value.into_clone_responder::()); + pub fn returns>(mut self, value: V) -> Quantify<'p, F, O> + where + <::Respond as Respond>::Get: IntoOutputResponder, + { + self.wrapper.push_output_responder_result( + value + .into_multi_response() + .map(|r| r.into_output_responder()), + ); self.quantify() } } @@ -248,14 +270,15 @@ macro_rules! define_response_common_impl { /// Specify the response of the call pattern by calling `Default::default()`. pub fn returns_default(mut self) -> Quantify<'p, F, O> where - ::Type: Default, + ::Type: Default, { - self.wrapper.push_responder( - InputsFnResponder:: { - func: crate::alloc::Box::new(|_| Default::default()), - } - .into_dyn_responder(), - ); + // self.wrapper.push_responder( + // InputsFnResponder:: { + // func: crate::alloc::Box::new(|_| Default::default()), + // } + // .into_dyn_responder(), + // ); + todo!(); self.quantify() } @@ -319,7 +342,8 @@ define_response_common_impl!(DefineMultipleResponses); pub struct QuantifyReturnValue<'p, F, T, O> where F: MockFn, - T: IntoOnceResponder, + T: IntoResponse, + <::Respond as Respond>::Get: IntoOutputResponder, { pub(crate) wrapper: DynBuilderWrapper<'p>, return_value: Option, @@ -330,15 +354,24 @@ where impl<'p, F, T, O> QuantifyReturnValue<'p, F, T, O> where F: MockFn, - T: IntoOnceResponder, + T: IntoResponse, O: Copy, + <::Respond as Respond>::Get: IntoOutputResponder, { /// Expect this call pattern to be matched exactly once. /// /// This is the only quantifier that works together with return values that don't implement [Clone]. - pub fn once(mut self) -> QuantifiedResponse<'p, F, O, Exact> { - self.wrapper - .push_responder_result(self.return_value.take().unwrap().into_once_responder::()); + pub fn once(mut self) -> QuantifiedResponse<'p, F, O, Exact> + where + <::Respond as Respond>::Get: IntoOutputResponder, + { + self.wrapper.push_output_responder_result( + self.return_value + .take() + .unwrap() + .into_response() + .map(|r| r.into_output_responder()), + ); self.wrapper.quantify(1, counter::Exactness::Exact); QuantifiedResponse { wrapper: self.wrapper.steal(), @@ -351,13 +384,15 @@ where /// Expect this call pattern to be matched exactly the specified number of times. pub fn n_times(mut self, times: usize) -> QuantifiedResponse<'p, F, O, Exact> where - T: IntoCloneResponder, + T: IntoMultiResponse, + <::Respond as Respond>::Get: IntoOutputResponder, { - self.wrapper.push_responder_result( + self.wrapper.push_output_responder_result( self.return_value .take() .unwrap() - .into_clone_responder::(), + .into_multi_response() + .map(|r| r.into_output_responder()), ); self.wrapper.quantify(times, counter::Exactness::Exact); QuantifiedResponse { @@ -374,14 +409,16 @@ where /// Strictly ordered call patterns must have exact quantification. pub fn at_least_times(mut self, times: usize) -> QuantifiedResponse<'p, F, O, AtLeast> where - T: IntoCloneResponder, + T: IntoMultiResponse, O: Ordering, + <::Respond as Respond>::Get: IntoOutputResponder, { - self.wrapper.push_responder_result( + self.wrapper.push_output_responder_result( self.return_value .take() .unwrap() - .into_clone_responder::(), + .into_multi_response() + .map(|r| r.into_output_responder()), ); self.wrapper.quantify(times, counter::Exactness::AtLeast); QuantifiedResponse { @@ -396,8 +433,9 @@ where impl<'p, F, T, O> Clause for QuantifyReturnValue<'p, F, T, O> where F: MockFn, - T: IntoOnceResponder, + T: IntoResponse, O: Copy + Ordering, + <::Respond as Respond>::Get: IntoOutputResponder, { fn deconstruct(self, sink: &mut dyn clause::term::Sink) -> Result<(), String> { self.once().deconstruct(sink) @@ -412,12 +450,16 @@ where impl<'p, F, T, O> Drop for QuantifyReturnValue<'p, F, T, O> where F: MockFn, - T: IntoOnceResponder, + T: IntoResponse, + <::Respond as Respond>::Get: IntoOutputResponder, { fn drop(&mut self) { if let Some(return_value) = self.return_value.take() { - self.wrapper - .push_responder_result(return_value.into_once_responder::()); + self.wrapper.push_output_responder_result( + return_value + .into_response() + .map(|r| r.into_output_responder()), + ); } } } diff --git a/src/call_pattern.rs b/src/call_pattern.rs index 32a4316..268a444 100644 --- a/src/call_pattern.rs +++ b/src/call_pattern.rs @@ -1,7 +1,7 @@ use crate::alloc::Vec; +use crate::respond::OutputResponder; use core::any::Any; -use crate::cell::DynCell; use crate::private::MismatchReporter; use crate::*; @@ -101,6 +101,7 @@ pub(crate) enum DynResponder { Cell(DynCellResponder), Borrow(DynBorrowResponder), InputsFn(DynInputsFnResponder), + Output(DynOutputResponder), StaticApply(DynStaticApplyResponder), BoxedApply(DynBoxedApplyResponder), Panic(Box), @@ -108,6 +109,7 @@ pub(crate) enum DynResponder { CallDefaultImpl, } +pub(crate) struct DynOutputResponder(AnyBox); pub(crate) struct DynCellResponder(AnyBox); pub(crate) struct DynBorrowResponder(AnyBox); pub(crate) struct DynInputsFnResponder(AnyBox); @@ -120,24 +122,32 @@ pub trait DowncastResponder { fn downcast(&self) -> PatternResult<&Self::Downcasted>; } -impl DowncastResponder for DynCellResponder { - type Downcasted = CellResponder; - - fn downcast(&self) -> PatternResult<&Self::Downcasted> { - downcast_box(&self.0) - } -} - -impl DowncastResponder for DynBorrowResponder { - type Downcasted = BorrowResponder; - - fn downcast(&self) -> PatternResult<&Self::Downcasted> { - downcast_box(&self.0) - } -} - -impl DowncastResponder for DynInputsFnResponder { - type Downcasted = InputsFnResponder; +// impl DowncastResponder for DynCellResponder { +// type Downcasted = CellResponder; +// +// fn downcast(&self) -> PatternResult<&Self::Downcasted> { +// downcast_box(&self.0) +// } +// } +// +// impl DowncastResponder for DynBorrowResponder { +// type Downcasted = BorrowResponder; +// +// fn downcast(&self) -> PatternResult<&Self::Downcasted> { +// downcast_box(&self.0) +// } +// } + +// impl DowncastResponder for DynInputsFnResponder { +// type Downcasted = InputsFnResponder; +// +// fn downcast(&self) -> PatternResult<&Self::Downcasted> { +// downcast_box(&self.0) +// } +// } + +impl DowncastResponder for DynOutputResponder { + type Downcasted = OutputResponder; fn downcast(&self) -> PatternResult<&Self::Downcasted> { downcast_box(&self.0) @@ -160,18 +170,18 @@ impl DowncastResponder for DynBoxedApplyResponder { } } -pub(crate) struct CellResponder { - pub cell: DynCell<::Type>, -} - -pub(crate) struct BorrowResponder { - pub borrowable: ::Type, -} +// pub(crate) struct CellResponder { +// pub cell: DynCell<::Type>, +// } +// +// pub(crate) struct BorrowResponder { +// pub borrowable: ::Type, +// } -pub(crate) struct InputsFnResponder { - #[allow(clippy::type_complexity)] - pub func: Box) -> ::Type) + Send + Sync>, -} +// pub(crate) struct InputsFnResponder { +// #[allow(clippy::type_complexity)] +// pub func: Box) -> ::Type) + Send + Sync>, +// } pub(crate) struct StaticApplyResponder { pub apply_fn: &'static F::ApplyFn, @@ -181,26 +191,32 @@ pub(crate) struct BoxedApplyResponder { pub apply_fn: Box, } -impl CellResponder { - pub fn into_dyn_responder(self) -> DynResponder { - DynResponder::Cell(DynCellResponder(Box::new(self))) - } -} - -impl BorrowResponder -where - ::Type: Send + Sync, -{ +impl OutputResponder { pub fn into_dyn_responder(self) -> DynResponder { - DynResponder::Borrow(DynBorrowResponder(Box::new(self))) + DynResponder::Output(DynOutputResponder(Box::new(self))) } } -impl InputsFnResponder { - pub fn into_dyn_responder(self) -> DynResponder { - DynResponder::InputsFn(DynInputsFnResponder(Box::new(self))) - } -} +// impl CellResponder { +// pub fn into_dyn_responder(self) -> DynResponder { +// DynResponder::Cell(DynCellResponder(Box::new(self))) +// } +// } + +// impl BorrowResponder +// where +// ::Type: Send + Sync, +// { +// pub fn into_dyn_responder(self) -> DynResponder { +// DynResponder::Borrow(DynBorrowResponder(Box::new(self))) +// } +// } +// +// impl InputsFnResponder { +// pub fn into_dyn_responder(self) -> DynResponder { +// DynResponder::InputsFn(DynInputsFnResponder(Box::new(self))) +// } +// } impl StaticApplyResponder { pub fn into_dyn_responder(self) -> DynResponder { diff --git a/src/cell.rs b/src/cell.rs index c1d3515..e9abde5 100644 --- a/src/cell.rs +++ b/src/cell.rs @@ -1,5 +1,5 @@ use crate::alloc::Box; -use crate::output::ResponderError; +use crate::respond::ResponderError; /// A cell that can be "taken from" pub struct DynCell(Box>); diff --git a/src/eval.rs b/src/eval.rs index c40507c..b0564dd 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,7 +6,6 @@ use crate::error::{self}; use crate::error::{MockError, MockResult}; use crate::fn_mocker::{FnMocker, PatternMatchMode}; use crate::mismatch::Mismatches; -use crate::output::Output; use crate::private::{ApplyClosure, Evaluation, MismatchReporter}; use crate::state::SharedState; use crate::{debug, MockFnInfo, Unimock}; @@ -36,52 +35,66 @@ pub(crate) fn eval<'u, 'i, F: MockFn>( match dyn_ctx.eval_dyn(&|pattern, reporter| pattern.match_inputs::(&inputs, reporter))? { EvalResult::Responder(eval_responder) => match eval_responder.dyn_responder { - DynResponder::Cell(dyn_cell_responder) => match dyn_ctx - .downcast_responder::(dyn_cell_responder, &eval_responder)? - .cell - .try_take() - { - Some(response) => { - let output = as Output<'u, F::Response>>::from_response( - *response, - &unimock.value_chain, - ); - - Ok(Evaluation::Evaluated(output)) - } - None => Err(MockError::CannotReturnValueMoreThanOnce { - fn_call: dyn_ctx.fn_call(), - pattern: eval_responder - .fn_mocker - .debug_pattern(eval_responder.pat_index), - }), - }, - DynResponder::Borrow(dyn_borrow_responder) => { - let borrow_responder = - dyn_ctx.downcast_responder::(dyn_borrow_responder, &eval_responder)?; - let output_result = - as Output<'u, F::Response>>::try_from_borrowed_response( - &borrow_responder.borrowable, - ); - - match output_result { - Ok(output) => Ok(Evaluation::Evaluated(output)), - Err(sig_err) => panic!( - "BUG: Signature error in {}: {:?}", - dyn_ctx.fn_call(), - sig_err - ), + DynResponder::Output(dyn_output_responder) => { + match dyn_ctx + .downcast_responder::(dyn_output_responder, &eval_responder)? + .respond() + { + Some(output) => Ok(Evaluation::Evaluated(output)), + None => Err(MockError::CannotReturnValueMoreThanOnce { + fn_call: dyn_ctx.fn_call(), + pattern: eval_responder + .fn_mocker + .debug_pattern(eval_responder.pat_index), + }), } } - DynResponder::InputsFn(dyn_fn_responder) => { - let fn_responder = - dyn_ctx.downcast_responder::(dyn_fn_responder, &eval_responder)?; - let output = as Output<'u, F::Response>>::from_response( - (fn_responder.func)(inputs), - &unimock.value_chain, - ); - Ok(Evaluation::Evaluated(output)) - } + // DynResponder::Cell(dyn_cell_responder) => match dyn_ctx + // .downcast_responder::(dyn_cell_responder, &eval_responder)? + // .cell + // .try_take() + // { + // Some(response) => { + // let output = as Output<'u, F::Response>>::from_response( + // *response, + // &unimock.value_chain, + // ); + // + // Ok(Evaluation::Evaluated(output)) + // } + // None => Err(MockError::CannotReturnValueMoreThanOnce { + // fn_call: dyn_ctx.fn_call(), + // pattern: eval_responder + // .fn_mocker + // .debug_pattern(eval_responder.pat_index), + // }), + // }, + // DynResponder::Borrow(dyn_borrow_responder) => { + // let borrow_responder = + // dyn_ctx.downcast_responder::(dyn_borrow_responder, &eval_responder)?; + // let output_result = + // as Output<'u, F::Response>>::try_from_borrowed_response( + // &borrow_responder.borrowable, + // ); + // + // match output_result { + // Ok(output) => Ok(Evaluation::Evaluated(output)), + // Err(sig_err) => panic!( + // "BUG: Signature error in {}: {:?}", + // dyn_ctx.fn_call(), + // sig_err + // ), + // } + // } + // DynResponder::InputsFn(dyn_fn_responder) => { + // let fn_responder = + // dyn_ctx.downcast_responder::(dyn_fn_responder, &eval_responder)?; + // let output = as Output<'u, F::Response>>::from_response( + // (fn_responder.func)(inputs), + // &unimock.value_chain, + // ); + // Ok(Evaluation::Evaluated(output)) + // } DynResponder::StaticApply(dyn_responder) => { let apply_fn_responder = dyn_ctx.downcast_responder::(dyn_responder, &eval_responder)?; @@ -113,6 +126,7 @@ pub(crate) fn eval<'u, 'i, F: MockFn>( }), DynResponder::Unmock => Ok(Evaluation::Unmocked(inputs)), DynResponder::CallDefaultImpl => Ok(Evaluation::CallDefaultImpl(inputs)), + _ => todo!(), }, EvalResult::Unmock => Ok(Evaluation::Unmocked(inputs)), EvalResult::CallDefaultImpl => Ok(Evaluation::CallDefaultImpl(inputs)), diff --git a/src/lib.rs b/src/lib.rs index 427d062..61481a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -450,14 +450,16 @@ pub mod alloc { /// Builder pattern types used for defining mocked behaviour. pub mod build; -/// Function outputs. -pub mod output; + +// /// Function outputs. +// pub mod output; + /// Traits and types used for describing the properties of various mock types. pub mod property; /// New output modelling pub mod respond; -pub mod response; +pub mod output; /// Mock APIs for various crates. pub mod mock; @@ -499,18 +501,23 @@ use core::fmt::Debug; use core::panic::RefUnwindSafe; use core::panic::UnwindSafe; -use call_pattern::BorrowResponder; -use call_pattern::CellResponder; -use cell::DynCell; +// use call_pattern::BorrowResponder; +// use call_pattern::CellResponder; +// use cell::DynCell; use once_cell::sync::OnceCell; use alloc::Box; use assemble::MockAssembler; use call_pattern::DynInputMatcher; use debug::TraitMethodPath; -use output::{IntoResponse, Respond, StaticRef}; +// use output::{IntoResponse, Respond, StaticRef}; use private::{DefaultImplDelegator, Matching}; +use respond::IntoConsumedResponse; +use respond::Respond; + +use output::StaticRefResponse; +use respond::StaticRef; /// /// Autogenerate mocks for all methods in the annotated traits, and `impl` it for [Unimock]. /// @@ -1037,10 +1044,7 @@ pub trait MockFn: Sized + 'static { /// The response value is Unimock's internal representation of the function's return value between two points it time: /// 1. The user specifies it upfront as part of a Clause. /// 2. The conversion of this value into the mocked function's final output value. - type Response: output::Respond; - - /// A type that describes the mocked function's actual output type. - type Output<'u>: output::Output<'u, Self::Response>; + type Respond: respond::Respond; /// The function type used for function application on a call pattern. type ApplyFn: ?Sized + Send + Sync; @@ -1216,41 +1220,43 @@ pub trait Clause { pub struct Responder(call_pattern::DynResponder); impl Responder { - pub(crate) fn cell(cell: DynCell<::Type>) -> Self - where - ::Type: Send + Sync + 'static, - { - Self(CellResponder:: { cell }.into_dyn_responder()) - } - - pub(crate) fn borrowing(response: ::Type) -> Self - where - ::Type: Send + Sync, - { - Responder( - BorrowResponder:: { - borrowable: response, - } - .into_dyn_responder(), - ) - } + // pub(crate) fn cell(cell: DynCell<::Type>) -> Self + // where + // ::Type: Send + Sync + 'static, + // { + // Self(CellResponder:: { cell }.into_dyn_responder()) + // } + // + // pub(crate) fn borrowing(response: ::Type) -> Self + // where + // ::Type: Send + Sync, + // { + // Responder( + // BorrowResponder:: { + // borrowable: response, + // } + // .into_dyn_responder(), + // ) + // } } /// A mocked response pub struct Response(ResponseInner); enum ResponseInner { - Response(::Type), - Unimock(&'static dyn Fn(Unimock) -> ::Type), + Response(::Consume), + Unimock(&'static dyn Fn(Unimock) -> ::Consume), } /// Turn a value into a mock function response. pub fn respond(input: T) -> Response where F: MockFn, - T: IntoResponse<::Response>, + T: IntoConsumedResponse<::Respond>, { - Response(ResponseInner::Response(input.into_response())) + Response(ResponseInner::Response( + input.into_consumed_response().unwrap(), + )) } /// Make a response that is a static reference to leaked memory. @@ -1259,19 +1265,23 @@ where /// on input parameters is necessary, which should not be a common use case. pub fn respond_leaked_ref(input: T) -> Response where - F: MockFn>, + F: MockFn>, T: core::borrow::Borrow + 'static, - R: 'static, + R: Send + Sync + 'static, { let response = >::borrow(Box::leak(Box::new(input))); - Response(ResponseInner::Response(response)) + Response(ResponseInner::Response(StaticRefResponse { + value: response, + })) } /// Respond with the unimock instance itself. pub fn respond_unimock() -> Response where F: MockFn, - Unimock: IntoResponse<::Response>, + Unimock: IntoConsumedResponse<::Respond>, { - Response(ResponseInner::Unimock(&|unimock| unimock.into_response())) + Response(ResponseInner::Unimock(&|unimock| { + unimock.into_consumed_response().unwrap() + })) } diff --git a/src/mock/std.rs b/src/mock/std.rs index d535081..211266b 100644 --- a/src/mock/std.rs +++ b/src/mock/std.rs @@ -76,7 +76,7 @@ pub mod process { /// Unimock mock API for [std::process::Termination]. #[allow(non_snake_case)] pub mod TerminationMock { - use crate::{output::Owned, MockFn, Response}; + use crate::{respond::Owned, MockFn, Response}; use std::{boxed::Box, string::String}; #[allow(non_camel_case_types)] @@ -88,8 +88,7 @@ pub mod process { impl MockFn for report { type Inputs<'i> = (); - type Response = Owned; - type Output<'u> = Self::Response; + type Respond = Owned; type ApplyFn = dyn Fn() -> Response + Send + Sync; fn info() -> crate::MockFnInfo { diff --git a/src/output.rs b/src/output.rs index e007516..13d2c36 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,712 +1,100 @@ -use core::borrow::Borrow; +use crate::{alloc::Box, respond::Respond, value_chain::ValueChain, MockFn}; -use crate::alloc::Box; -use crate::{cell::DynCell, value_chain::ValueChain, MockFn, Responder}; - -#[derive(Debug)] #[doc(hidden)] -pub enum ResponderError { - OwnershipRequired, - NoMutexApi, -} - -type OutputResult = Result; +pub trait Get: Sized + 'static { + type Output<'u> + where + Self: 'u; -/// Trait for responding to function calls. -pub trait Respond { - /// The type of the response, as stored temporarily inside Unimock. - type Type: 'static; + fn get(&self) -> Option>; } -/// Trait for values that can be converted into responses. -pub trait IntoResponse { - // Convert this type into the output type. - #[doc(hidden)] - fn into_response(self) -> ::Type; -} +#[doc(hidden)] +pub trait Consume: Sized + 'static { + type Output<'u> + where + Self: 'u; -/// Types that may converted into a responder that responds once. -/// -/// This can be implemented by types that do not implement `Clone`. -pub trait IntoOnceResponder: IntoResponse { - #[doc(hidden)] - fn into_once_responder>(self) -> OutputResult; + fn consume<'u>(self, value_chain: &'u ValueChain) -> Self::Output<'u>; } -/// Types that may converted into a responder that responds any number of times. -pub trait IntoCloneResponder: IntoOnceResponder { - #[doc(hidden)] - fn into_clone_responder>(self) -> OutputResult; +#[doc(hidden)] +pub trait MockFnGet { + fn get_mock_output(&self) -> Option<<::Get as Get>::Output<'_>>; } -/// Trait that describes the output of a mocked function, and how responses are converted into that type. -/// -/// The trait uses the 'u lifetime, which is the lifetime of unimock itself. -/// This way it's possible to borrow values stored inside the instance. -pub trait Output<'u, R: Respond> { - /// The type of the output compatible with the function signature. - type Type; - - #[doc(hidden)] - fn from_response(response: R::Type, value_chain: &'u ValueChain) -> Self::Type; - - #[doc(hidden)] - fn try_from_borrowed_response(response: &'u R::Type) -> OutputResult; +impl MockFnGet for G +where + for<'u> G: Get = <::Get as Get>::Output<'u>>, +{ + fn get_mock_output( + &self, + ) -> Option<<<::Respond as Respond>::Get as Get>::Output<'_>> { + ::get(&self) + } } #[doc(hidden)] -pub struct Owned(core::marker::PhantomData); - -// This type describes a function response that is a reference borrowed from `Self`. -#[doc(hidden)] -pub struct Borrowed(core::marker::PhantomData); - -#[doc(hidden)] -pub struct StaticRef(core::marker::PhantomData); - -// This type describes a function response that is a mix of owned and borrowed data. -// -// The typical example is `Option<&T>`. -#[doc(hidden)] -pub struct Mixed(core::marker::PhantomData); - -/// Generic values -#[doc(hidden)] -pub struct Generic(core::marker::PhantomData); - -type BoxBorrow = Box + Send + Sync>; - -mod owned { - use super::*; - - impl Respond for Owned { - type Type = T; - } - - impl IntoResponse> for T0 - where - T0: Into, - { - fn into_response(self) -> as Respond>::Type { - self.into() - } - } - - impl IntoOnceResponder> for T0 - where - T0: Into, - { - fn into_once_responder>>(self) -> OutputResult { - let response = >>::into_response(self); - Ok(Responder::cell::(DynCell::once(response)?)) - } - } - - impl IntoCloneResponder> for T0 - where - T0: Into, - { - fn into_clone_responder>>(self) -> OutputResult { - let response = >>::into_response(self); - Ok(Responder::cell::(DynCell::clonable(response))) - } - } - - impl<'u, T: 'static> Output<'u, Self> for Owned { - type Type = T; - - fn from_response(response: ::Type, _: &'u ValueChain) -> Self::Type { - response - } - - fn try_from_borrowed_response(_: &'u ::Type) -> OutputResult { - Err(ResponderError::OwnershipRequired) - } - } +pub struct FuncResponse { + pub(crate) factory: Box Option + Send + Sync + 'static>, } -mod borrowed { - use super::*; - - impl Respond for Borrowed { - type Type = Box + Send + Sync>; - } +impl Get for FuncResponse { + type Output<'u> = T where Self: 'u; - impl IntoResponse> for T0 - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - { - fn into_response(self) -> as Respond>::Type { - Box::new(self) - } - } - - impl IntoOnceResponder> for T0 - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - { - fn into_once_responder>>(self) -> OutputResult { - let response = >>::into_response(self); - Ok(Responder::borrowing::(response)) - } - } - - impl IntoCloneResponder> for T0 - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - { - fn into_clone_responder>>( - self, - ) -> OutputResult { - >>::into_once_responder::(self) - } - } - - impl<'u, T: ?Sized + 'static> Output<'u, Self> for Borrowed { - type Type = &'u T; - - fn from_response( - response: ::Type, - value_chain: &'u ValueChain, - ) -> Self::Type { - let value_ref = value_chain.add(response); - - value_ref.as_ref().borrow() - } - - fn try_from_borrowed_response( - response: &'u ::Type, - ) -> OutputResult { - Ok(response.as_ref().borrow()) - } + fn get(&self) -> Option> { + (*self.factory)() } } -mod static_ref { - use super::*; - - impl Respond for StaticRef { - type Type = &'static T; - } - - impl IntoResponse> for &'static T { - fn into_response(self) -> as Respond>::Type { - self - } - } - - impl IntoOnceResponder> for &'static T { - fn into_once_responder>>( - self, - ) -> OutputResult { - let response = >>::into_response(self); - Ok(Responder::borrowing::(response)) - } - } - - impl IntoCloneResponder> for &'static T { - fn into_clone_responder>>( - self, - ) -> OutputResult { - >>::into_once_responder::(self) - } - } - - impl<'u, T: ?Sized + 'static> Output<'u, Self> for StaticRef { - type Type = &'static T; - - fn from_response(value: ::Type, _: &ValueChain) -> Self::Type { - value - } +impl Consume for FuncResponse { + type Output<'u> = T where Self: 'u; - fn try_from_borrowed_response( - value: &'u ::Type, - ) -> OutputResult { - Ok(*value) - } + fn consume<'u>(self, _value_chain: &'u ValueChain) -> Self::Output<'u> { + (*self.factory)().expect("output value could not be consumed. This is a bug.") } } -// TODO: Generalize in mixed enum macro. -mod mixed_option { - use super::*; - - type Mix = Mixed>; - - impl Respond for Mix { - type Type = Option>; - } - - impl IntoResponse> for Option - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - { - fn into_response(self) -> as Respond>::Type { - match self { - Some(value) => Some(Box::new(value)), - None => None, - } - } - } - - impl IntoOnceResponder> for Option - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - { - fn into_once_responder>>(self) -> OutputResult { - let response = >>::into_response(self); - Ok(Responder::borrowing::(response)) - } - } - - impl IntoCloneResponder> for Option - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - { - fn into_clone_responder>>(self) -> OutputResult { - let response = >>::into_response(self); - Ok(Responder::borrowing::(response)) - } - } - - impl<'u, T> Output<'u, Mix> for Mixed> - where - T: ?Sized + 'u, - { - type Type = Option<&'u T>; - - fn from_response( - response: as Respond>::Type, - value_chain: &'u ValueChain, - ) -> Self::Type { - response.map(|value| value_chain.add(value).as_ref().borrow()) - } - - fn try_from_borrowed_response( - response: &'u as Respond>::Type, - ) -> OutputResult { - Ok(response.as_ref().map(|value| value.as_ref().borrow())) - } - } +pub struct ConsumableResponse { + pub(crate) value: T, } -mod mixed_vec { - use crate::alloc::Vec; - - use super::*; - - type Mix = Mixed>; - - impl Respond for Mix { - type Type = Vec>; - } - - impl IntoResponse> for Vec - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - { - fn into_response(self) -> as Respond>::Type { - self.into_iter() - .map(|item| -> BoxBorrow { Box::new(item) }) - .collect() - } - } - - impl IntoOnceResponder> for Vec - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - { - fn into_once_responder>>(self) -> OutputResult { - let response = >>::into_response(self); - Ok(Responder::borrowing::(response)) - } - } - - impl IntoCloneResponder> for Vec - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - { - fn into_clone_responder>>(self) -> OutputResult { - let response = >>::into_response(self); - Ok(Responder::borrowing::(response)) - } - } - - impl<'u, T> Output<'u, Mix> for Mixed> - where - T: ?Sized + 'u, - { - type Type = Vec<&'u T>; - - fn from_response(_: as Respond>::Type, _: &'u ValueChain) -> Self::Type { - panic!() - } +impl Get for ConsumableResponse { + type Output<'u> = T + where + Self: 'u; - fn try_from_borrowed_response( - response: &'u as Respond>::Type, - ) -> OutputResult { - Ok(response.iter().map(|b| b.as_ref().borrow()).collect()) - } + fn get(&self) -> Option> { + None } } -// TODO: Generalize in mixed enum macro. -mod mixed_result_borrowed_t { - use super::*; - - type Mix = Mixed>; - - impl Respond for Mix { - type Type = Result, E>; - } - - impl IntoResponse> for Result - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - E: Send + Sync + 'static, - { - fn into_response(self) -> as Respond>::Type { - match self { - Ok(value) => Ok(Box::new(value)), - Err(e) => Err(e), - } - } - } - - impl IntoOnceResponder> for Result - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - E: Send + Sync + 'static, - { - fn into_once_responder>>(self) -> OutputResult { - match self { - // In the Ok variant we make a multi-value responder out of it anyway: - Ok(value) => Ok(Responder::borrowing::(Ok(Box::new(value)))), - // The Err variant can only be used once: - Err(error) => Ok(Responder::cell::(DynCell::once(Err(error))?)), - } - } - } - - impl IntoCloneResponder> for Result - where - T0: Borrow + Send + Sync + 'static, - T: ?Sized + 'static, - E: Clone + Send + Sync + 'static, - { - fn into_clone_responder>>(self) -> OutputResult { - match self { - // There is no `T0: Clone` bound, because it just uses the borrow responder mechanism: - Ok(value) => Ok(Responder::borrowing::(Ok(Box::new(value)))), - // We have `E: Clone` because the E is in fact owned... - Err(error) => Ok(Responder::cell::(DynCell::func(move || { - Some(Err(error.clone())) - }))), - } - } - } - - impl<'u, T, E: 'static> Output<'u, Mix> for Mixed> - where - T: ?Sized + 'u, - { - type Type = Result<&'u T, E>; - - fn from_response( - response: as Respond>::Type, - value_chain: &'u ValueChain, - ) -> Self::Type { - match response { - Ok(value) => Ok(value_chain.add(value).as_ref().borrow()), - Err(e) => Err(e), - } - } +impl Consume for ConsumableResponse { + type Output<'u> = T + where + Self: 'u; - fn try_from_borrowed_response( - response: &'u as Respond>::Type, - ) -> OutputResult { - match response { - Ok(value) => Ok(Ok(value.as_ref().borrow())), - // No chance of converting the E into owned here: - Err(_) => Err(ResponderError::OwnershipRequired), - } - } + fn consume<'u>(self, _value_chain: &'u ValueChain) -> Self::Output<'u> { + self.value } } -macro_rules! mixed_tuples { - ($(($t:ident, $a:ident, $i:tt)),+) => { - impl<$($t: Respond),+> Respond for Mixed<($($t),+,)> { - type Type = ($(<$t as Respond>::Type),+,); - } - - impl<$($t),+, $($a),+> IntoResponse> for ($($a),+,) - where - $($t: Respond),+, - $(<$t as Respond>::Type: Send + Sync),+, - $($a: IntoResponse<$t>),+, - { - fn into_response(self) -> as Respond>::Type { - ($(self.$i.into_response()),+,) - } - } - - impl<$($t),+, $($a),+> IntoOnceResponder> for ($($a),+,) - where - $($t: Respond),+, - $(<$t as Respond>::Type: Send + Sync),+, - $($a: IntoResponse<$t>),+, - { - fn into_once_responder>>(self) -> OutputResult { - let response = >>::into_response(self); - Ok(Responder::cell::(DynCell::once(response)?)) - } - } - - - impl<$($t),+, $($a),+> IntoCloneResponder> for ($($a),+,) - where - $($t: Respond),+, - $(<$t as Respond>::Type: Clone + Send + Sync),+, - $($a: IntoCloneResponder<$t>),+, - { - fn into_clone_responder>>(self) -> OutputResult { - let response = >>::into_response(self); - Ok(Responder::cell::(DynCell::clonable(response))) - } - } - - impl<'u, $($t),+, $($a),+> Output<'u, Mixed<($($t),+,)>> for Mixed<($($a),+,)> - where - $($t: Respond),+, - $($a: Output<'u, $t>),+, - { - type Type = ($(<$a as Output<'u, $t>>::Type),+,); - - fn from_response( - response: as Respond>::Type, - value_chain: &'u ValueChain, - ) -> Self::Type { - ( - $(<$a as Output<'u, $t>>::from_response(response.$i, value_chain)),+, - ) - } - - fn try_from_borrowed_response( - response: &'u as Respond>::Type, - ) -> OutputResult { - Ok(( - $(<$a as Output<'u, $t>>::try_from_borrowed_response(&response.$i)?),+, - )) - } - } - }; +pub struct StaticRefResponse { + pub(crate) value: &'static T, } -mixed_tuples!((T0, A0, 0)); -mixed_tuples!((T0, A0, 0), (T1, A1, 1)); -mixed_tuples!((T0, A0, 0), (T1, A1, 1), (T2, A2, 2)); -mixed_tuples!((T0, A0, 0), (T1, A1, 1), (T2, A2, 2), (T3, A3, 3)); - -// This can perhaps serve as the template for a macro that handles Mixed enums -mod mixed_poll { - use super::*; - use core::task::Poll; - - type Mix = Mixed>; - - impl Respond for Mix - where - Mixed: Respond, - as Respond>::Type: 'static + Send + Sync, - { - type Type = Poll< as Respond>::Type>; - } - - impl IntoResponse> for Poll - where - T0: IntoResponse>, - Mixed: Respond, - as Respond>::Type: 'static + Send + Sync, - { - fn into_response(self) -> as Respond>::Type { - match self { - Poll::Ready(value) => Poll::Ready(value.into_response()), - Poll::Pending => Poll::Pending, - } - } - } - - impl IntoOnceResponder> for Poll - where - T0: IntoResponse>, - Mixed: Respond, - as Respond>::Type: 'static + Send + Sync, - { - fn into_once_responder>>(self) -> OutputResult { - match self { - Poll::Ready(value) => Ok(Responder::cell::(DynCell::once(Poll::Ready( - value.into_response(), - ))?)), - Poll::Pending => Ok(Responder::cell::(DynCell::func(|| Some(Poll::Pending)))), - } - } - } - - impl IntoCloneResponder> for Poll - where - T0: IntoResponse>, - Mixed: Respond, - as Respond>::Type: 'static + Send + Sync + Clone, - { - fn into_clone_responder>>(self) -> OutputResult { - match self { - Poll::Ready(value) => Ok(Responder::cell::(DynCell::clonable(Poll::Ready( - value.into_response(), - )))), - Poll::Pending => Ok(Responder::cell::(DynCell::func(|| Some(Poll::Pending)))), - } - } - } - - impl<'u, T, A> Output<'u, Mix> for Mixed> - where - Mixed: Respond, - as Respond>::Type: 'static + Send + Sync, - Mixed: Output<'u, Mixed>, - { - type Type = Poll< as Output<'u, Mixed>>::Type>; - - fn from_response( - response: as Respond>::Type, - value_chain: &'u ValueChain, - ) -> Self::Type { - match response { - Poll::Ready(value) => Poll::Ready( - as Output<'u, Mixed>>::from_response(value, value_chain), - ), - Poll::Pending => Poll::Pending, - } - } +impl Get for StaticRefResponse { + type Output<'u> = &'static T; - fn try_from_borrowed_response( - response: &'u as Respond>::Type, - ) -> OutputResult { - Ok(match response { - Poll::Ready(value) => Poll::Ready( - as Output<'u, Mixed>>::try_from_borrowed_response(value)?, - ), - Poll::Pending => Poll::Pending, - }) - } + fn get(&self) -> Option> { + Some(self.value) } } -mod generic_result { - use super::*; - - type G = Generic>; - - impl Respond for G - where - T: Respond, - ::Type: 'static + Send + Sync, - E: Respond, - ::Type: 'static + Send + Sync, - { - type Type = Result<::Type, ::Type>; - } - - impl IntoResponse> for Result - where - T: Respond, - ::Type: 'static + Send + Sync, - T0: IntoResponse, - E: Respond, - ::Type: 'static + Send + Sync, - E0: IntoResponse, - { - fn into_response(self) -> as Respond>::Type { - match self { - Ok(value) => Ok(value.into_response()), - Err(error) => Err(error.into_response()), - } - } - } - - impl IntoOnceResponder> for Result - where - T: Respond, - ::Type: 'static + Send + Sync, - T0: IntoResponse, - E: Respond, - ::Type: 'static + Send + Sync, - E0: IntoResponse, - { - fn into_once_responder>>(self) -> OutputResult { - Ok(match self { - Ok(val) => Responder::cell::(DynCell::once(Ok(val.into_response()))?), - Err(val) => Responder::cell::(DynCell::once(Err(val.into_response()))?), - }) - } - } - - impl IntoCloneResponder> for Result - where - T: Respond, - ::Type: 'static + Send + Sync + Clone, - T0: IntoResponse, - E: Respond, - ::Type: 'static + Send + Sync + Clone, - E0: IntoResponse, - { - fn into_clone_responder>>(self) -> OutputResult { - Ok(match self { - Ok(val) => Responder::cell::(DynCell::clonable(Ok(val.into_response()))), - Err(val) => Responder::cell::(DynCell::clonable(Err(val.into_response()))), - }) - } - } - - impl<'u, T, T1, E, E1> Output<'u, G> for Generic> - where - T: Respond, - ::Type: 'static + Send + Sync, - T1: Output<'u, T>, - E: Respond, - ::Type: 'static + Send + Sync, - E1: Output<'u, E>, - { - type Type = Result<>::Type, >::Type>; - - fn from_response( - response: as Respond>::Type, - value_chain: &'u ValueChain, - ) -> Self::Type { - match response { - Ok(val) => Ok(>::from_response(val, value_chain)), - Err(val) => Err(>::from_response(val, value_chain)), - } - } +impl Consume for StaticRefResponse { + type Output<'u> = &'static T; - fn try_from_borrowed_response( - response: &'u as Respond>::Type, - ) -> OutputResult { - Ok(match response { - Ok(val) => Ok(>::try_from_borrowed_response(val)?), - Err(val) => Err(>::try_from_borrowed_response(val)?), - }) - } + fn consume<'u>(self, _value_chain: &'u ValueChain) -> Self::Output<'u> { + self.value } } diff --git a/src/output_old.rs b/src/output_old.rs new file mode 100644 index 0000000..e007516 --- /dev/null +++ b/src/output_old.rs @@ -0,0 +1,712 @@ +use core::borrow::Borrow; + +use crate::alloc::Box; +use crate::{cell::DynCell, value_chain::ValueChain, MockFn, Responder}; + +#[derive(Debug)] +#[doc(hidden)] +pub enum ResponderError { + OwnershipRequired, + NoMutexApi, +} + +type OutputResult = Result; + +/// Trait for responding to function calls. +pub trait Respond { + /// The type of the response, as stored temporarily inside Unimock. + type Type: 'static; +} + +/// Trait for values that can be converted into responses. +pub trait IntoResponse { + // Convert this type into the output type. + #[doc(hidden)] + fn into_response(self) -> ::Type; +} + +/// Types that may converted into a responder that responds once. +/// +/// This can be implemented by types that do not implement `Clone`. +pub trait IntoOnceResponder: IntoResponse { + #[doc(hidden)] + fn into_once_responder>(self) -> OutputResult; +} + +/// Types that may converted into a responder that responds any number of times. +pub trait IntoCloneResponder: IntoOnceResponder { + #[doc(hidden)] + fn into_clone_responder>(self) -> OutputResult; +} + +/// Trait that describes the output of a mocked function, and how responses are converted into that type. +/// +/// The trait uses the 'u lifetime, which is the lifetime of unimock itself. +/// This way it's possible to borrow values stored inside the instance. +pub trait Output<'u, R: Respond> { + /// The type of the output compatible with the function signature. + type Type; + + #[doc(hidden)] + fn from_response(response: R::Type, value_chain: &'u ValueChain) -> Self::Type; + + #[doc(hidden)] + fn try_from_borrowed_response(response: &'u R::Type) -> OutputResult; +} + +#[doc(hidden)] +pub struct Owned(core::marker::PhantomData); + +// This type describes a function response that is a reference borrowed from `Self`. +#[doc(hidden)] +pub struct Borrowed(core::marker::PhantomData); + +#[doc(hidden)] +pub struct StaticRef(core::marker::PhantomData); + +// This type describes a function response that is a mix of owned and borrowed data. +// +// The typical example is `Option<&T>`. +#[doc(hidden)] +pub struct Mixed(core::marker::PhantomData); + +/// Generic values +#[doc(hidden)] +pub struct Generic(core::marker::PhantomData); + +type BoxBorrow = Box + Send + Sync>; + +mod owned { + use super::*; + + impl Respond for Owned { + type Type = T; + } + + impl IntoResponse> for T0 + where + T0: Into, + { + fn into_response(self) -> as Respond>::Type { + self.into() + } + } + + impl IntoOnceResponder> for T0 + where + T0: Into, + { + fn into_once_responder>>(self) -> OutputResult { + let response = >>::into_response(self); + Ok(Responder::cell::(DynCell::once(response)?)) + } + } + + impl IntoCloneResponder> for T0 + where + T0: Into, + { + fn into_clone_responder>>(self) -> OutputResult { + let response = >>::into_response(self); + Ok(Responder::cell::(DynCell::clonable(response))) + } + } + + impl<'u, T: 'static> Output<'u, Self> for Owned { + type Type = T; + + fn from_response(response: ::Type, _: &'u ValueChain) -> Self::Type { + response + } + + fn try_from_borrowed_response(_: &'u ::Type) -> OutputResult { + Err(ResponderError::OwnershipRequired) + } + } +} + +mod borrowed { + use super::*; + + impl Respond for Borrowed { + type Type = Box + Send + Sync>; + } + + impl IntoResponse> for T0 + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + { + fn into_response(self) -> as Respond>::Type { + Box::new(self) + } + } + + impl IntoOnceResponder> for T0 + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + { + fn into_once_responder>>(self) -> OutputResult { + let response = >>::into_response(self); + Ok(Responder::borrowing::(response)) + } + } + + impl IntoCloneResponder> for T0 + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + { + fn into_clone_responder>>( + self, + ) -> OutputResult { + >>::into_once_responder::(self) + } + } + + impl<'u, T: ?Sized + 'static> Output<'u, Self> for Borrowed { + type Type = &'u T; + + fn from_response( + response: ::Type, + value_chain: &'u ValueChain, + ) -> Self::Type { + let value_ref = value_chain.add(response); + + value_ref.as_ref().borrow() + } + + fn try_from_borrowed_response( + response: &'u ::Type, + ) -> OutputResult { + Ok(response.as_ref().borrow()) + } + } +} + +mod static_ref { + use super::*; + + impl Respond for StaticRef { + type Type = &'static T; + } + + impl IntoResponse> for &'static T { + fn into_response(self) -> as Respond>::Type { + self + } + } + + impl IntoOnceResponder> for &'static T { + fn into_once_responder>>( + self, + ) -> OutputResult { + let response = >>::into_response(self); + Ok(Responder::borrowing::(response)) + } + } + + impl IntoCloneResponder> for &'static T { + fn into_clone_responder>>( + self, + ) -> OutputResult { + >>::into_once_responder::(self) + } + } + + impl<'u, T: ?Sized + 'static> Output<'u, Self> for StaticRef { + type Type = &'static T; + + fn from_response(value: ::Type, _: &ValueChain) -> Self::Type { + value + } + + fn try_from_borrowed_response( + value: &'u ::Type, + ) -> OutputResult { + Ok(*value) + } + } +} + +// TODO: Generalize in mixed enum macro. +mod mixed_option { + use super::*; + + type Mix = Mixed>; + + impl Respond for Mix { + type Type = Option>; + } + + impl IntoResponse> for Option + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + { + fn into_response(self) -> as Respond>::Type { + match self { + Some(value) => Some(Box::new(value)), + None => None, + } + } + } + + impl IntoOnceResponder> for Option + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + { + fn into_once_responder>>(self) -> OutputResult { + let response = >>::into_response(self); + Ok(Responder::borrowing::(response)) + } + } + + impl IntoCloneResponder> for Option + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + { + fn into_clone_responder>>(self) -> OutputResult { + let response = >>::into_response(self); + Ok(Responder::borrowing::(response)) + } + } + + impl<'u, T> Output<'u, Mix> for Mixed> + where + T: ?Sized + 'u, + { + type Type = Option<&'u T>; + + fn from_response( + response: as Respond>::Type, + value_chain: &'u ValueChain, + ) -> Self::Type { + response.map(|value| value_chain.add(value).as_ref().borrow()) + } + + fn try_from_borrowed_response( + response: &'u as Respond>::Type, + ) -> OutputResult { + Ok(response.as_ref().map(|value| value.as_ref().borrow())) + } + } +} + +mod mixed_vec { + use crate::alloc::Vec; + + use super::*; + + type Mix = Mixed>; + + impl Respond for Mix { + type Type = Vec>; + } + + impl IntoResponse> for Vec + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + { + fn into_response(self) -> as Respond>::Type { + self.into_iter() + .map(|item| -> BoxBorrow { Box::new(item) }) + .collect() + } + } + + impl IntoOnceResponder> for Vec + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + { + fn into_once_responder>>(self) -> OutputResult { + let response = >>::into_response(self); + Ok(Responder::borrowing::(response)) + } + } + + impl IntoCloneResponder> for Vec + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + { + fn into_clone_responder>>(self) -> OutputResult { + let response = >>::into_response(self); + Ok(Responder::borrowing::(response)) + } + } + + impl<'u, T> Output<'u, Mix> for Mixed> + where + T: ?Sized + 'u, + { + type Type = Vec<&'u T>; + + fn from_response(_: as Respond>::Type, _: &'u ValueChain) -> Self::Type { + panic!() + } + + fn try_from_borrowed_response( + response: &'u as Respond>::Type, + ) -> OutputResult { + Ok(response.iter().map(|b| b.as_ref().borrow()).collect()) + } + } +} + +// TODO: Generalize in mixed enum macro. +mod mixed_result_borrowed_t { + use super::*; + + type Mix = Mixed>; + + impl Respond for Mix { + type Type = Result, E>; + } + + impl IntoResponse> for Result + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + E: Send + Sync + 'static, + { + fn into_response(self) -> as Respond>::Type { + match self { + Ok(value) => Ok(Box::new(value)), + Err(e) => Err(e), + } + } + } + + impl IntoOnceResponder> for Result + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + E: Send + Sync + 'static, + { + fn into_once_responder>>(self) -> OutputResult { + match self { + // In the Ok variant we make a multi-value responder out of it anyway: + Ok(value) => Ok(Responder::borrowing::(Ok(Box::new(value)))), + // The Err variant can only be used once: + Err(error) => Ok(Responder::cell::(DynCell::once(Err(error))?)), + } + } + } + + impl IntoCloneResponder> for Result + where + T0: Borrow + Send + Sync + 'static, + T: ?Sized + 'static, + E: Clone + Send + Sync + 'static, + { + fn into_clone_responder>>(self) -> OutputResult { + match self { + // There is no `T0: Clone` bound, because it just uses the borrow responder mechanism: + Ok(value) => Ok(Responder::borrowing::(Ok(Box::new(value)))), + // We have `E: Clone` because the E is in fact owned... + Err(error) => Ok(Responder::cell::(DynCell::func(move || { + Some(Err(error.clone())) + }))), + } + } + } + + impl<'u, T, E: 'static> Output<'u, Mix> for Mixed> + where + T: ?Sized + 'u, + { + type Type = Result<&'u T, E>; + + fn from_response( + response: as Respond>::Type, + value_chain: &'u ValueChain, + ) -> Self::Type { + match response { + Ok(value) => Ok(value_chain.add(value).as_ref().borrow()), + Err(e) => Err(e), + } + } + + fn try_from_borrowed_response( + response: &'u as Respond>::Type, + ) -> OutputResult { + match response { + Ok(value) => Ok(Ok(value.as_ref().borrow())), + // No chance of converting the E into owned here: + Err(_) => Err(ResponderError::OwnershipRequired), + } + } + } +} + +macro_rules! mixed_tuples { + ($(($t:ident, $a:ident, $i:tt)),+) => { + impl<$($t: Respond),+> Respond for Mixed<($($t),+,)> { + type Type = ($(<$t as Respond>::Type),+,); + } + + impl<$($t),+, $($a),+> IntoResponse> for ($($a),+,) + where + $($t: Respond),+, + $(<$t as Respond>::Type: Send + Sync),+, + $($a: IntoResponse<$t>),+, + { + fn into_response(self) -> as Respond>::Type { + ($(self.$i.into_response()),+,) + } + } + + impl<$($t),+, $($a),+> IntoOnceResponder> for ($($a),+,) + where + $($t: Respond),+, + $(<$t as Respond>::Type: Send + Sync),+, + $($a: IntoResponse<$t>),+, + { + fn into_once_responder>>(self) -> OutputResult { + let response = >>::into_response(self); + Ok(Responder::cell::(DynCell::once(response)?)) + } + } + + + impl<$($t),+, $($a),+> IntoCloneResponder> for ($($a),+,) + where + $($t: Respond),+, + $(<$t as Respond>::Type: Clone + Send + Sync),+, + $($a: IntoCloneResponder<$t>),+, + { + fn into_clone_responder>>(self) -> OutputResult { + let response = >>::into_response(self); + Ok(Responder::cell::(DynCell::clonable(response))) + } + } + + impl<'u, $($t),+, $($a),+> Output<'u, Mixed<($($t),+,)>> for Mixed<($($a),+,)> + where + $($t: Respond),+, + $($a: Output<'u, $t>),+, + { + type Type = ($(<$a as Output<'u, $t>>::Type),+,); + + fn from_response( + response: as Respond>::Type, + value_chain: &'u ValueChain, + ) -> Self::Type { + ( + $(<$a as Output<'u, $t>>::from_response(response.$i, value_chain)),+, + ) + } + + fn try_from_borrowed_response( + response: &'u as Respond>::Type, + ) -> OutputResult { + Ok(( + $(<$a as Output<'u, $t>>::try_from_borrowed_response(&response.$i)?),+, + )) + } + } + }; +} + +mixed_tuples!((T0, A0, 0)); +mixed_tuples!((T0, A0, 0), (T1, A1, 1)); +mixed_tuples!((T0, A0, 0), (T1, A1, 1), (T2, A2, 2)); +mixed_tuples!((T0, A0, 0), (T1, A1, 1), (T2, A2, 2), (T3, A3, 3)); + +// This can perhaps serve as the template for a macro that handles Mixed enums +mod mixed_poll { + use super::*; + use core::task::Poll; + + type Mix = Mixed>; + + impl Respond for Mix + where + Mixed: Respond, + as Respond>::Type: 'static + Send + Sync, + { + type Type = Poll< as Respond>::Type>; + } + + impl IntoResponse> for Poll + where + T0: IntoResponse>, + Mixed: Respond, + as Respond>::Type: 'static + Send + Sync, + { + fn into_response(self) -> as Respond>::Type { + match self { + Poll::Ready(value) => Poll::Ready(value.into_response()), + Poll::Pending => Poll::Pending, + } + } + } + + impl IntoOnceResponder> for Poll + where + T0: IntoResponse>, + Mixed: Respond, + as Respond>::Type: 'static + Send + Sync, + { + fn into_once_responder>>(self) -> OutputResult { + match self { + Poll::Ready(value) => Ok(Responder::cell::(DynCell::once(Poll::Ready( + value.into_response(), + ))?)), + Poll::Pending => Ok(Responder::cell::(DynCell::func(|| Some(Poll::Pending)))), + } + } + } + + impl IntoCloneResponder> for Poll + where + T0: IntoResponse>, + Mixed: Respond, + as Respond>::Type: 'static + Send + Sync + Clone, + { + fn into_clone_responder>>(self) -> OutputResult { + match self { + Poll::Ready(value) => Ok(Responder::cell::(DynCell::clonable(Poll::Ready( + value.into_response(), + )))), + Poll::Pending => Ok(Responder::cell::(DynCell::func(|| Some(Poll::Pending)))), + } + } + } + + impl<'u, T, A> Output<'u, Mix> for Mixed> + where + Mixed: Respond, + as Respond>::Type: 'static + Send + Sync, + Mixed: Output<'u, Mixed>, + { + type Type = Poll< as Output<'u, Mixed>>::Type>; + + fn from_response( + response: as Respond>::Type, + value_chain: &'u ValueChain, + ) -> Self::Type { + match response { + Poll::Ready(value) => Poll::Ready( + as Output<'u, Mixed>>::from_response(value, value_chain), + ), + Poll::Pending => Poll::Pending, + } + } + + fn try_from_borrowed_response( + response: &'u as Respond>::Type, + ) -> OutputResult { + Ok(match response { + Poll::Ready(value) => Poll::Ready( + as Output<'u, Mixed>>::try_from_borrowed_response(value)?, + ), + Poll::Pending => Poll::Pending, + }) + } + } +} + +mod generic_result { + use super::*; + + type G = Generic>; + + impl Respond for G + where + T: Respond, + ::Type: 'static + Send + Sync, + E: Respond, + ::Type: 'static + Send + Sync, + { + type Type = Result<::Type, ::Type>; + } + + impl IntoResponse> for Result + where + T: Respond, + ::Type: 'static + Send + Sync, + T0: IntoResponse, + E: Respond, + ::Type: 'static + Send + Sync, + E0: IntoResponse, + { + fn into_response(self) -> as Respond>::Type { + match self { + Ok(value) => Ok(value.into_response()), + Err(error) => Err(error.into_response()), + } + } + } + + impl IntoOnceResponder> for Result + where + T: Respond, + ::Type: 'static + Send + Sync, + T0: IntoResponse, + E: Respond, + ::Type: 'static + Send + Sync, + E0: IntoResponse, + { + fn into_once_responder>>(self) -> OutputResult { + Ok(match self { + Ok(val) => Responder::cell::(DynCell::once(Ok(val.into_response()))?), + Err(val) => Responder::cell::(DynCell::once(Err(val.into_response()))?), + }) + } + } + + impl IntoCloneResponder> for Result + where + T: Respond, + ::Type: 'static + Send + Sync + Clone, + T0: IntoResponse, + E: Respond, + ::Type: 'static + Send + Sync + Clone, + E0: IntoResponse, + { + fn into_clone_responder>>(self) -> OutputResult { + Ok(match self { + Ok(val) => Responder::cell::(DynCell::clonable(Ok(val.into_response()))), + Err(val) => Responder::cell::(DynCell::clonable(Err(val.into_response()))), + }) + } + } + + impl<'u, T, T1, E, E1> Output<'u, G> for Generic> + where + T: Respond, + ::Type: 'static + Send + Sync, + T1: Output<'u, T>, + E: Respond, + ::Type: 'static + Send + Sync, + E1: Output<'u, E>, + { + type Type = Result<>::Type, >::Type>; + + fn from_response( + response: as Respond>::Type, + value_chain: &'u ValueChain, + ) -> Self::Type { + match response { + Ok(val) => Ok(>::from_response(val, value_chain)), + Err(val) => Err(>::from_response(val, value_chain)), + } + } + + fn try_from_borrowed_response( + response: &'u as Respond>::Type, + ) -> OutputResult { + Ok(match response { + Ok(val) => Ok(>::try_from_borrowed_response(val)?), + Err(val) => Err(>::try_from_borrowed_response(val)?), + }) + } + } +} diff --git a/src/private.rs b/src/private.rs index 8ea83a8..08d6bf9 100644 --- a/src/private.rs +++ b/src/private.rs @@ -2,7 +2,8 @@ use core::ops::Deref; use crate::call_pattern::InputIndex; use crate::mismatch::{Mismatch, MismatchKind}; -use crate::output::Output; +use crate::output::Consume; +// use crate::output::Output; use crate::{call_pattern::MatchingFn, *}; use crate::alloc::{vec, String, Vec}; @@ -17,7 +18,7 @@ pub use crate::default_impl_delegator::*; #[non_exhaustive] pub enum Evaluation<'u, 'i, F: MockFn> { /// Function evaluated to its output. - Evaluated( as Output<'u, F::Response>>::Type), + Evaluated(<::Get as output::Get>::Output<'u>), /// Function should be applied Apply(ApplyClosure<'u, F>, F::Inputs<'i>), /// Function not yet evaluated, should be unmocked. @@ -30,7 +31,10 @@ impl<'u, 'i, F: MockFn> Evaluation<'u, 'i, F> { /// Unwrap the `Evaluated` variant, or panic. /// The unimock instance must be passed in order to register that an eventual panic happened. #[track_caller] - pub fn unwrap(self, unimock: &Unimock) -> as Output<'u, F::Response>>::Type { + pub fn unwrap( + self, + unimock: &Unimock, + ) -> <::Get as output::Get>::Output<'u> { let error = match self { Self::Evaluated(output) => return output, Self::Apply(..) => error::MockError::NotApplied { info: F::info() }, @@ -59,16 +63,23 @@ impl<'u, F: MockFn> Deref for ApplyClosure<'u, F> { impl<'u, F: MockFn> ApplyClosure<'u, F> { pub fn __to_output( &self, - response: Response, - ) -> as Output<'u, F::Response>>::Type { - let response = match response.0 { - ResponseInner::Response(response) => response, - ResponseInner::Unimock(func) => func(self.unimock.clone()), - }; - as output::Output<'u, ::Response>>::from_response( - response, - &self.unimock.value_chain, - ) + response: crate::Response, + ) -> <::Get as output::Get>::Output<'u> { + // let response = match response.0 { + // ResponseInner::Response(response) => response, + // ResponseInner::Unimock(func) => func(self.unimock.clone()), + // }; + // as output::Output<'u, ::Response>>::from_response( + // response, + // &self.unimock.value_chain, + // ) + + match response.0 { + ResponseInner::Response(repsonse) => repsonse.consume(&self.unimock.value_chain), + ResponseInner::Unimock(func) => { + func(self.unimock.clone()).consume(&self.unimock.value_chain) + } + } } } diff --git a/src/respond.rs b/src/respond.rs index 9ab7e5d..4cc5c53 100644 --- a/src/respond.rs +++ b/src/respond.rs @@ -1,17 +1,10 @@ use crate::{ alloc::Box, - response::{GetOutput, Response}, + output::{self, Consume, Get, MockFnGet}, value_chain::ValueChain, + MockFn, }; -#[doc(hidden)] -pub trait MockFn2: 'static { - type Respond: Respond; - - // A type that describes the mocked function's actual output type. - type Output<'u>; -} - #[derive(Debug)] #[doc(hidden)] pub enum ResponderError { @@ -26,31 +19,45 @@ pub trait Respond: 'static { /// The type of the response, as stored temporarily inside Unimock. type Type: 'static; - type Response: Response; + type Get: Get; + type Consume: for<'u> Consume = ::Output<'u>>; } #[doc(hidden)] pub trait IntoResponse { #[doc(hidden)] - fn into_response(self) -> ResponderResult; + fn into_response(self) -> ResponderResult; } #[doc(hidden)] pub trait IntoMultiResponse: IntoResponse { #[doc(hidden)] - fn into_multi_response(self) -> ResponderResult; + fn into_multi_response(self) -> ResponderResult; } #[doc(hidden)] -pub trait IntoMockResponder { - fn into_mock_responder(self) -> MockResponder; +pub trait IntoConsumedResponse { + #[doc(hidden)] + fn into_consumed_response(self) -> ResponderResult; } -pub struct MockResponder(pub(crate) Box>); +#[doc(hidden)] +pub trait IntoOutputResponder { + fn into_output_responder(self) -> OutputResponder; +} -impl MockResponder { - pub(crate) fn respond(&self) -> Option> { - self.0.get_output() +impl + Send + Sync + 'static> IntoOutputResponder for R { + fn into_output_responder(self) -> OutputResponder { + OutputResponder(Box::new(self)) + } +} + +#[doc(hidden)] +pub struct OutputResponder(pub(crate) Box + Send + Sync + 'static>); + +impl OutputResponder { + pub(crate) fn respond(&self) -> Option<<::Get as Get>::Output<'_>> { + self.0.get_mock_output() } } @@ -59,21 +66,25 @@ impl MockResponder { pub struct Owned(core::marker::PhantomData); #[doc(hidden)] -pub struct Borrowed(core::marker::PhantomData); +pub struct Lent(core::marker::PhantomData); -/// A respondable where T is generic #[doc(hidden)] -pub struct Generic(core::marker::PhantomData); +pub struct StaticRef(core::marker::PhantomData); + +/// A respond where T is generic and contains borrowed parameters +#[doc(hidden)] +pub struct Mixed(core::marker::PhantomData); mod owned { - use crate::response::FuncResponse; + use crate::output::{ConsumableResponse, FuncResponse}; use super::*; impl Respond for Owned { type Type = T; - type Response = FuncResponse; + type Get = FuncResponse; + type Consume = ConsumableResponse; } impl IntoResponse> for T0 @@ -100,369 +111,445 @@ mod owned { }) } } + + impl IntoConsumedResponse> for T0 + where + T0: Into, + { + fn into_consumed_response(self) -> ResponderResult> { + Ok(ConsumableResponse { value: self.into() }) + } + } } -mod borrowed { +mod lent { use core::borrow::Borrow; use super::*; - impl Respond for Borrowed { + impl Respond for Lent { type Type = Box + Send + Sync>; - type Response = Borrower; + type Get = Lend; + type Consume = Lend; } - impl IntoResponse> for T0 + impl IntoResponse> for T0 where T0: Borrow + Send + Sync + 'static, { - fn into_response(self) -> ResponderResult> { - Ok(Borrower { + fn into_response(self) -> ResponderResult> { + Ok(Lend { value: Box::new(self), }) } } - impl IntoMultiResponse> for T0 + impl IntoMultiResponse> for T0 where T0: Borrow + Send + Sync + 'static, { - fn into_multi_response(self) -> ResponderResult> { - Ok(Borrower { + fn into_multi_response(self) -> ResponderResult> { + Ok(Lend { value: Box::new(self), }) } } - pub struct Borrower { + impl IntoConsumedResponse> for T0 + where + T0: Borrow + Send + Sync + 'static, + { + fn into_consumed_response(self) -> ResponderResult> { + Ok(Lend { + value: Box::new(self), + }) + } + } + + pub struct Lend { value: Box + Send + Sync>, } - impl Response for Borrower { + impl Get for Lend { type Output<'u> = &'u T where Self: 'u; - fn get_output(&self) -> Option> { + fn get(&self) -> Option> { Some(self.value.as_ref().borrow()) } + } + + impl output::Consume for Lend { + type Output<'u> = &'u T + where + Self: 'u; - fn into_output<'u>(self, value_chain: &'u ValueChain) -> Option> { + fn consume<'u>(self, value_chain: &'u ValueChain) -> Self::Output<'u> { let value = value_chain.add(self.value); - Some(value.as_ref().borrow()) + value.as_ref().borrow() + } + } +} + +mod static_ref { + use crate::output::StaticRefResponse; + + use super::*; + + impl Respond for StaticRef { + type Type = &'static T; + + type Get = StaticRefResponse; + type Consume = StaticRefResponse; + } + + impl IntoResponse> for &'static T { + fn into_response(self) -> ResponderResult> { + Ok(StaticRefResponse { value: self }) + } + } + + impl IntoMultiResponse> for &'static T { + fn into_multi_response(self) -> ResponderResult> { + Ok(StaticRefResponse { value: self }) + } + } + + impl IntoConsumedResponse> for &'static T { + fn into_consumed_response(self) -> ResponderResult> { + Ok(StaticRefResponse { value: self }) } } } -mod generic_result { +mod mixed_option { use super::*; - type G = Generic>; + type M = Mixed>; - impl Respond for G + impl Respond for M where T: Respond, ::Type: 'static + Send + Sync, - E: Respond, - ::Type: 'static + Send + Sync, { - type Type = Result<::Type, ::Type>; + type Type = Option<::Type>; - type Response = ResultOutputter; + type Get = GetOptionResponse; + type Consume = ConsumeOptionResponse; } - impl IntoResponse> for Result + impl IntoResponse> for Option where T: Respond, ::Type: 'static + Send + Sync, T0: IntoResponse, - E: Respond, - ::Type: 'static + Send + Sync, - E0: IntoResponse, { - fn into_response(self) -> ResponderResult> { + fn into_response(self) -> ResponderResult> { match self { - Ok(val) => Ok(ResultOutputter::Ok(val.into_response()?)), - Err(val) => Ok(ResultOutputter::Err(val.into_response()?)), + Some(val) => Ok(GetOptionResponse::Some(val.into_response()?)), + None => Ok(GetOptionResponse::None), } } } - impl IntoMultiResponse> for Result + impl IntoMultiResponse> for Option where T: Respond, ::Type: 'static + Send + Sync, T0: IntoMultiResponse, - E: Respond, - ::Type: 'static + Send + Sync, - E0: IntoMultiResponse, { - fn into_multi_response(self) -> ResponderResult> { + fn into_multi_response(self) -> ResponderResult> { match self { - Ok(val) => Ok(ResultOutputter::Ok(val.into_multi_response()?)), - Err(val) => Ok(ResultOutputter::Err(val.into_multi_response()?)), + Some(val) => Ok(GetOptionResponse::Some(val.into_multi_response()?)), + None => Ok(GetOptionResponse::None), } } } - pub enum ResultOutputter { - Ok(T::Response), - Err(E::Response), + impl IntoConsumedResponse> for Option + where + T: Respond, + ::Type: 'static + Send + Sync, + T0: IntoConsumedResponse, + { + fn into_consumed_response(self) -> ResponderResult> { + match self { + Some(val) => Ok(ConsumeOptionResponse::Some(val.into_consumed_response()?)), + None => Ok(ConsumeOptionResponse::None), + } + } } - impl Response for ResultOutputter + pub enum GetOptionResponse { + Some(T::Get), + None, + } + + impl Get for GetOptionResponse where T: Respond, - E: Respond, Self: 'static, { type Output<'u> = - Result< - <::Response as Response>::Output<'u>, - <::Response as Response>::Output<'u>, + Option< + <::Get as Get>::Output<'u>, > where Self: 'u; - fn get_output(&self) -> Option> { + fn get(&self) -> Option> { match self { - Self::Ok(val) => Some(Ok(val.get_output()?)), - Self::Err(val) => Some(Err(val.get_output()?)), + Self::Some(val) => Some(Some(val.get()?)), + Self::None => Some(None), } } + } - fn into_output<'u>(self, value_chain: &'u ValueChain) -> Option> { - match self { - Self::Ok(val) => Some(Ok(val.into_output(value_chain)?)), - Self::Err(val) => Some(Err(val.into_output(value_chain)?)), - } - } + pub enum ConsumeOptionResponse { + Some(T::Consume), + None, } - impl IntoMockResponder for ResultOutputter + impl Consume for ConsumeOptionResponse where - T: Respond + 'static, - E: Respond + 'static, - F: for<'u> MockFn2 = ::Output<'u>>, + T: Respond, + Self: 'static, { - fn into_mock_responder(self) -> MockResponder { - MockResponder(Box::new(self)) + type Output<'u> = + Option< + <::Consume as Consume>::Output<'u>, + > + where + Self: 'u; + + fn consume<'u>(self, value_chain: &'u ValueChain) -> Self::Output<'u> { + match self { + Self::Some(val) => Some(val.consume(value_chain)), + Self::None => None, + } } } } -mod generic_poll { - use core::task::Poll; - +mod mixed_result { use super::*; - type G = Generic>; + type M = Mixed>; - impl Respond for G + impl Respond for M where T: Respond, ::Type: 'static + Send + Sync, + E: Respond, + ::Type: 'static + Send + Sync, { - type Type = Poll<::Type>; + type Type = Result<::Type, ::Type>; - type Response = PollOutputter; + type Get = GetResultResponse; + type Consume = ConsumeResultResponse; } - impl IntoResponse> for Poll + impl IntoResponse> for Result where T: Respond, ::Type: 'static + Send + Sync, T0: IntoResponse, + E: Respond, + ::Type: 'static + Send + Sync, + E0: IntoResponse, { - fn into_response(self) -> ResponderResult> { + fn into_response(self) -> ResponderResult> { match self { - Self::Ready(val) => Ok(PollOutputter::Ready(val.into_response()?)), - Self::Pending => Ok(PollOutputter::Pending), + Ok(val) => Ok(GetResultResponse::Ok(val.into_response()?)), + Err(val) => Ok(GetResultResponse::Err(val.into_response()?)), } } } - impl IntoMultiResponse> for Poll + impl IntoMultiResponse> for Result where T: Respond, ::Type: 'static + Send + Sync, T0: IntoMultiResponse, + E: Respond, + ::Type: 'static + Send + Sync, + E0: IntoMultiResponse, { - fn into_multi_response(self) -> ResponderResult> { + fn into_multi_response(self) -> ResponderResult> { match self { - Self::Ready(val) => Ok(PollOutputter::Ready(val.into_multi_response()?)), - Self::Pending => Ok(PollOutputter::Pending), + Ok(val) => Ok(GetResultResponse::Ok(val.into_multi_response()?)), + Err(val) => Ok(GetResultResponse::Err(val.into_multi_response()?)), } } } - pub enum PollOutputter { - Ready(T::Response), - Pending, + impl IntoConsumedResponse> for Result + where + T: Respond, + ::Type: 'static + Send + Sync, + T0: IntoConsumedResponse, + E: Respond, + ::Type: 'static + Send + Sync, + E0: IntoConsumedResponse, + { + fn into_consumed_response(self) -> ResponderResult> { + match self { + Ok(val) => Ok(ConsumeResultResponse::Ok(val.into_consumed_response()?)), + Err(val) => Ok(ConsumeResultResponse::Err(val.into_consumed_response()?)), + } + } + } + + pub enum GetResultResponse { + Ok(T::Get), + Err(E::Get), } - impl Response for PollOutputter + impl Get for GetResultResponse where T: Respond, + E: Respond, Self: 'static, { type Output<'u> = - Poll< - <::Response as Response>::Output<'u>, + Result< + <::Get as Get>::Output<'u>, + <::Get as Get>::Output<'u>, > where Self: 'u; - fn get_output(&self) -> Option> { + fn get(&self) -> Option> { match self { - Self::Ready(val) => Some(Poll::Ready(val.get_output()?)), - Self::Pending => Some(Poll::Pending), + Self::Ok(val) => Some(Ok(val.get()?)), + Self::Err(val) => Some(Err(val.get()?)), } } + } - fn into_output<'u>(self, value_chain: &'u ValueChain) -> Option> { - match self { - Self::Ready(val) => Some(Poll::Ready(val.into_output(value_chain)?)), - Self::Pending => Some(Poll::Pending), - } - } + pub enum ConsumeResultResponse { + Ok(T::Consume), + Err(E::Consume), } - impl IntoMockResponder for PollOutputter + impl Consume for ConsumeResultResponse where - T: Respond + 'static, - F: for<'u> MockFn2 = ::Output<'u>>, + T: Respond, + E: Respond, + Self: 'static, { - fn into_mock_responder(self) -> MockResponder { - MockResponder(Box::new(self)) + type Output<'u> = + Result< + <::Consume as Consume>::Output<'u>, + <::Consume as Consume>::Output<'u>, + > + where + Self: 'u; + + fn consume<'u>(self, value_chain: &'u ValueChain) -> Self::Output<'u> { + match self { + Self::Ok(val) => Ok(val.consume(value_chain)), + Self::Err(val) => Err(val.consume(value_chain)), + } } } } -#[cfg(test)] -mod tests { - use crate::alloc::BTreeMap; - - use super::IntoMockResponder; - use core::{ - any::{Any, TypeId}, - marker::PhantomData, - task::Poll, - }; +mod mixed_poll { + use core::task::Poll; use super::*; - #[derive(Default)] - struct ResultMock; - - impl MockFn2 for ResultMock { - type Respond = Generic, Borrowed>>; - type Output<'u> = Result; - } - - #[derive(Default)] - struct PollResultMock; + type G = Mixed>; - impl MockFn2 for PollResultMock { - type Respond = Generic, Borrowed>>>>; - type Output<'u> = Poll>; - } + impl Respond for G + where + T: Respond, + ::Type: 'static + Send + Sync, + { + type Type = Poll<::Type>; - #[derive(Default)] - struct Resp { - ph: PhantomData, + type Get = GetPollResponse; + type Consume = ConsumePollResponse; } - impl Resp { - fn resp(&self, val: T) -> MockResponder - where - T: IntoResponse, - <::Respond as Respond>::Response: IntoMockResponder, - { - val.into_response().unwrap().into_mock_responder() + impl IntoResponse> for Poll + where + T: Respond, + ::Type: 'static + Send + Sync, + T0: IntoResponse, + { + fn into_response(self) -> ResponderResult> { + match self { + Self::Ready(val) => Ok(GetPollResponse::Ready(val.into_response()?)), + Self::Pending => Ok(GetPollResponse::Pending), + } } } - enum EvalResult<'u, F: MockFn2> + impl IntoMultiResponse> for Poll where - <::Respond as Respond>::Response: 'u, + T: Respond, + ::Type: 'static + Send + Sync, + T0: IntoMultiResponse, { - Evaluated(::Output<'u>), + fn into_multi_response(self) -> ResponderResult> { + match self { + Self::Ready(val) => Ok(GetPollResponse::Ready(val.into_multi_response()?)), + Self::Pending => Ok(GetPollResponse::Pending), + } + } } - #[derive(Default)] - struct MiniMock { - responders: BTreeMap>, + pub enum GetPollResponse { + Ready(T::Get), + Pending, } - impl MiniMock { - fn mock(&mut self, value: T) - where - F: MockFn2, - T: IntoResponse, - <::Respond as Respond>::Response: IntoMockResponder, - { - let responder = value.into_response().unwrap(); - self.responders - .insert(TypeId::of::(), Box::new(responder.into_mock_responder())); - } - - fn mock_multi(&mut self, value: T) - where - F: MockFn2, - T: IntoMultiResponse, - <::Respond as Respond>::Response: IntoMockResponder, - { - let responder = value.into_multi_response().unwrap(); - self.responders - .insert(TypeId::of::(), Box::new(responder.into_mock_responder())); - } - - fn eval<'u, F: MockFn2>(&'u self) -> EvalResult<'u, F> { - let dyn_resp = self.responders.get(&TypeId::of::()).unwrap(); - - let mock_resp = dyn_resp.downcast_ref::>().unwrap(); + impl Get for GetPollResponse + where + T: Respond, + Self: 'static, + { + type Output<'u> = + Poll< + <::Get as Get>::Output<'u>, + > + where + Self: 'u; - EvalResult::Evaluated(mock_resp.respond().unwrap()) + fn get(&self) -> Option> { + match self { + Self::Ready(val) => Some(Poll::Ready(val.get()?)), + Self::Pending => Some(Poll::Pending), + } } } - #[test] - fn mini_result_mock() { - let mut mini = MiniMock::default(); - - mini.mock::(Err::(64)); - - mini.mock_multi::(Err::(64)); - - assert!(matches!( - mini.eval::(), - EvalResult::Evaluated(Err(&64)) - )); - } - - #[test] - fn mini_poll_result_mock() { - let mut mini = MiniMock::default(); - - mini.mock::(Poll::>::Pending); - mini.mock::(Poll::Ready(Err::(64))); - - assert!(matches!( - mini.eval::(), - EvalResult::Evaluated(Poll::Ready(Err(&64))) - )); + pub enum ConsumePollResponse { + Ready(T::Consume), + Pending, } - #[test] - fn yo() { - let r: Resp = Default::default(); - - let mr = r.resp(Ok::<_, i64>(42)); - assert_eq!(mr.respond(), Some(Ok(42))); + impl Consume for ConsumePollResponse + where + T: Respond, + Self: 'static, + { + type Output<'u> = + Poll< + <::Consume as Consume>::Output<'u>, + > + where + Self: 'u; - let mr = r.resp(Err::(42)); - assert_eq!(mr.respond(), Some(Err(&42))); + fn consume<'u>(self, value_chain: &'u ValueChain) -> Self::Output<'u> { + match self { + Self::Ready(val) => Poll::Ready(val.consume(value_chain)), + Self::Pending => Poll::Pending, + } + } } } diff --git a/src/response.rs b/src/response.rs deleted file mode 100644 index 6da4dde..0000000 --- a/src/response.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::{ - alloc::Box, - respond::{IntoMockResponder, MockFn2, MockResponder}, - value_chain::ValueChain, -}; - -#[doc(hidden)] -pub trait Response: Sized + 'static { - type Output<'u> - where - Self: 'u; - - fn get_output(&self) -> Option>; - - fn into_output<'u>(self, value_chain: &'u ValueChain) -> Option>; -} - -pub trait GetOutput { - fn get_output(&self) -> Option>; -} - -pub trait IntoOutput<'u, F: MockFn2> { - fn into_output(self, value_chain: &'u ValueChain) -> Option>; -} - -impl GetOutput for T -where - for<'u> T: Response = ::Output<'u>> + 'static, -{ - fn get_output(&self) -> Option<::Output<'_>> { - ::get_output(&self) - } -} - -impl<'u, F: MockFn2, T> IntoOutput<'u, F> for T -where - T: Response = ::Output<'u>> + 'static, -{ - fn into_output(self, value_chain: &'u ValueChain) -> Option<::Output<'u>> { - ::into_output(self, value_chain) - } -} - -#[doc(hidden)] -pub struct CloneResponse { - value: T, -} - -impl Response for CloneResponse { - type Output<'u> = T where Self: 'u; - - fn get_output(&self) -> Option> { - Some(self.value.clone()) - } - - fn into_output<'u>(self, _value_chain: &'u ValueChain) -> Option> { - Some(self.value) - } -} - -impl IntoMockResponder for CloneResponse -where - for<'u> F: MockFn2 = ::Output<'u>>, -{ - fn into_mock_responder(self) -> MockResponder { - MockResponder(Box::new(self)) - } -} - -#[doc(hidden)] -pub struct FuncResponse { - pub(crate) factory: Box Option + Send + Sync + 'static>, -} - -impl Response for FuncResponse { - type Output<'u> = T where Self: 'u; - - fn get_output(&self) -> Option> { - (*self.factory)() - } - - fn into_output<'u>(self, _value_chain: &'u ValueChain) -> Option> { - (*self.factory)() - } -} diff --git a/tests/it/mixed.rs b/tests/it/mixed.rs index 6359be6..784f3ee 100644 --- a/tests/it/mixed.rs +++ b/tests/it/mixed.rs @@ -68,13 +68,13 @@ fn in_result() { let u = Unimock::new(( InResultMock::bytes .next_call(matching!()) - .returns(Ok(vec![42])), + .returns(Ok::<_, clone::Nope>(vec![42])), InResultMock::bytes .next_call(matching!()) .returns(Err::<&[u8], _>(clone::Nope)), InResultMock::u32_clone .each_call(matching!()) - .returns(Ok(42)) + .returns(Ok::<_, clone::Sure>(42)) .at_least_times(2), )); @@ -89,7 +89,7 @@ fn in_result_clone_acrobatics() { let u = Unimock::new(( InResultMock::ok_no_clone .each_call(matching!(true)) - .returns(Ok(clone::Nope)), + .returns(Ok::<_, clone::Sure>(clone::Nope)), InResultMock::ok_no_clone .each_call(matching!(false)) .returns(Err::<&clone::Nope, _>(clone::Sure)), @@ -114,7 +114,7 @@ fn in_result_may_multi_respond_on_ok_no_clone() { let u = Unimock::new( InResultMock::ok_no_clone .some_call(matching!(_)) - .returns(Ok(clone::Nope)), + .returns(Ok::<_, clone::Sure>(clone::Nope)), ); assert_eq!(Ok(&clone::Nope), u.ok_no_clone(true)); diff --git a/tests/it/output_generic.rs b/tests/it/output_generic.rs index 5a8835b..fd3803e 100644 --- a/tests/it/output_generic.rs +++ b/tests/it/output_generic.rs @@ -27,13 +27,12 @@ mod InResultMock { pub struct u32_clone; } -use unimock::output::*; +use unimock::respond::*; const _: () = { impl ::unimock::MockFn for InResultMock::bytes { type Inputs<'__i> = (); - type Response = Generic, Owned>>; - type Output<'u> = Generic, Owned>>; + type Respond = Mixed, Owned>>; type ApplyFn = dyn Fn() -> Response + Send + Sync; fn info() -> ::unimock::MockFnInfo { ::unimock::MockFnInfo::new::().path(&["InResult", "bytes"]) @@ -41,8 +40,7 @@ const _: () = { } impl ::unimock::MockFn for InResultMock::u32_clone { type Inputs<'__i> = (); - type Response = Generic, Owned>>; - type Output<'u> = Generic, Owned>>; + type Respond = Mixed, Owned>>; type ApplyFn = dyn Fn() -> Response + Send + Sync; fn info() -> ::unimock::MockFnInfo { ::unimock::MockFnInfo::new::().path(&["InResult", "bytes"]) @@ -77,7 +75,8 @@ fn output_generic() { .returns(Err::<&[u8], _>(clone::Nope)), InResultMock::u32_clone .next_call(matching!()) - .returns(Ok::(42)), // .n_times(2), + .returns(Ok::(42)) + .n_times(2), )); assert_eq!(Ok(vec![42].as_slice()), ::bytes(&u)); diff --git a/unimock_macros/src/unimock/mod.rs b/unimock_macros/src/unimock/mod.rs index db20204..c98bf56 100644 --- a/unimock_macros/src/unimock/mod.rs +++ b/unimock_macros/src/unimock/mod.rs @@ -259,10 +259,7 @@ fn def_mock_fn( let response_assoc_type = method .output_structure - .response_associated_type(prefix, trait_info, attr); - let output_assoc_type = method - .output_structure - .output_associated_type(prefix, trait_info, attr); + .respond_associated_type(prefix, trait_info, attr); let apply_fn_params = method .adapted_sig .inputs @@ -297,8 +294,7 @@ fn def_mock_fn( #(#mirrored_attrs)* impl #generic_params #prefix::MockFn for #mock_fn_path #generic_args #where_clause { type Inputs<#input_lifetime> = #input_types_tuple; - type Response = #response_assoc_type; - type Output<'u> = #output_assoc_type; + type Respond = #response_assoc_type; type ApplyFn = dyn Fn(#(#apply_fn_params),*) -> #prefix::Response + Send + Sync; fn info() -> #prefix::MockFnInfo { @@ -329,7 +325,7 @@ fn def_mock_fn( self ) -> impl for<#input_lifetime> #prefix::MockFn< Inputs<#input_lifetime> = #input_types_tuple, - Response = #response_assoc_type, + Respond = #response_assoc_type, ApplyFn = <#mock_fn_ident #generic_args as #prefix::MockFn>::ApplyFn, > #where_clause diff --git a/unimock_macros/src/unimock/output.rs b/unimock_macros/src/unimock/output.rs index 3feaad0..9c7f464 100644 --- a/unimock_macros/src/unimock/output.rs +++ b/unimock_macros/src/unimock/output.rs @@ -1,6 +1,6 @@ use proc_macro2::TokenStream; use quote::quote; -use syn::{parse_quote, visit_mut::VisitMut}; +use syn::{parse_quote, visit_mut::VisitMut, PathArguments}; use super::{ trait_info::TraitInfo, @@ -10,41 +10,27 @@ use super::{ pub struct OutputStructure { pub wrapping: OutputWrapping, - pub ownership: OutputOwnership, - response_ty: AssociatedInnerType, - output_ty: AssociatedInnerType, + pub respond_kind: RespondKind, + respond_ty: AssociatedInnerType, } impl OutputStructure { - pub fn response_associated_type( + pub fn respond_associated_type( &self, prefix: &syn::Path, trait_info: &TraitInfo, attr: &Attr, ) -> proc_macro2::TokenStream { - let response_ty = self.response_ty.self_type_to_unimock(trait_info, attr); + let response_ty = self.respond_ty.self_type_to_unimock(trait_info, attr); self.render_associated_type(prefix, &response_ty) } - pub fn output_associated_type( - &self, - prefix: &syn::Path, - trait_info: &TraitInfo, - attr: &Attr, - ) -> proc_macro2::TokenStream { - let output_ty = self.output_ty.self_type_to_unimock(trait_info, attr); - self.render_associated_type(prefix, &output_ty) - } - fn render_associated_type( &self, prefix: &syn::Path, associated_type: &AssociatedInnerType, ) -> proc_macro2::TokenStream { let inner = match associated_type { - AssociatedInnerType::SameAsResponse => { - return quote! { Self::Response }; - } AssociatedInnerType::Unit => { quote! { () } } @@ -53,9 +39,9 @@ impl OutputStructure { } }; - let response_type_ident = self.ownership.response_type_ident(); + let response_type_ident = self.respond_kind.response_type_ident(); quote! { - #prefix::output::#response_type_ident<#inner> + #prefix::respond::#response_type_ident<#inner> } } } @@ -66,7 +52,7 @@ pub enum OutputWrapping { AssociatedFuture(syn::TraitItemType), } -pub enum OutputOwnership { +pub enum RespondKind { Owned, SelfReference, ParamReference, @@ -74,15 +60,15 @@ pub enum OutputOwnership { Mixed, } -impl OutputOwnership { +impl RespondKind { fn response_type_ident(&self) -> syn::Ident { - syn::Ident::new(self.response_typename(), proc_macro2::Span::call_site()) + syn::Ident::new(self.respond_typename(), proc_macro2::Span::call_site()) } - pub fn response_typename(&self) -> &'static str { + pub fn respond_typename(&self) -> &'static str { match self { Self::Owned => "Owned", - Self::SelfReference => "Borrowed", + Self::SelfReference => "Lent", Self::ParamReference => "StaticRef", Self::StaticReference => "StaticRef", Self::Mixed => "Mixed", @@ -99,25 +85,18 @@ pub fn determine_output_structure( match &sig.output { syn::ReturnType::Default => OutputStructure { wrapping: OutputWrapping::None, - ownership: OutputOwnership::Owned, - response_ty: AssociatedInnerType::Unit, - output_ty: AssociatedInnerType::Unit, + respond_kind: RespondKind::Owned, + respond_ty: AssociatedInnerType::Unit, }, syn::ReturnType::Type(_, output_ty) => match output_ty.as_ref() { syn::Type::Reference(type_reference) => { let mut inner_ty = *type_reference.elem.clone(); let borrow_info = ReturnTypeAnalyzer::analyze_borrows(sig, &mut inner_ty); - let ownership = determine_reference_ownership(sig, type_reference); OutputStructure { wrapping: OutputWrapping::None, - ownership: determine_reference_ownership(sig, type_reference), - response_ty: AssociatedInnerType::new_static(inner_ty, &borrow_info), - output_ty: AssociatedInnerType::new_gat( - *type_reference.elem.clone(), - &borrow_info, - &ownership, - ), + respond_kind: determine_reference_ownership(sig, type_reference), + respond_ty: AssociatedInnerType::new_static(inner_ty, &borrow_info), } } syn::Type::Path(output_path) @@ -154,78 +133,96 @@ pub fn determine_owned_or_mixed_output_structure( output_ty: &syn::Type, attr: &Attr, ) -> OutputStructure { - let prefix = &attr.prefix; - let output_ty = output_ty.clone(); let mut inner_ty = output_ty.clone(); let borrow_info = ReturnTypeAnalyzer::analyze_borrows(sig, &mut inner_ty); let ownership = if borrow_info.has_input_lifetime { - OutputOwnership::Owned + RespondKind::Owned } else if borrow_info.has_elided_reference || borrow_info.has_self_reference { - OutputOwnership::Mixed + RespondKind::Mixed } else { - OutputOwnership::Owned + RespondKind::Owned }; match (ownership, inner_ty) { - (OutputOwnership::Mixed, syn::Type::Tuple(tuple)) => { + (RespondKind::Mixed, syn::Type::Tuple(tuple)) => { let mut response_ty_tuple = syn::TypeTuple { paren_token: syn::token::Paren::default(), elems: Default::default(), }; - let mut output_ty_tuple = syn::TypeTuple { - paren_token: syn::token::Paren::default(), - elems: Default::default(), - }; for elem in tuple.elems { - match elem { - syn::Type::Reference(reference) => { - let elem = reference.elem; - - if reference.mutability.is_some() { - panic!("TODO: Mutable references in tuples"); - } - - response_ty_tuple.elems.push(parse_quote! { - #prefix::output::Borrowed<#elem> - }); - output_ty_tuple.elems.push(parse_quote! { - #prefix::output::Borrowed<#elem> - }); - } - owned => { - response_ty_tuple.elems.push(parse_quote! { - #prefix::output::Owned<#owned> - }); - output_ty_tuple.elems.push(parse_quote! { - #prefix::output::Owned<#owned> - }); - } - } + response_ty_tuple.elems.push(make_mixed(elem, attr)); } response_ty_tuple.elems.push_punct(Default::default()); - output_ty_tuple.elems.push_punct(Default::default()); OutputStructure { wrapping: OutputWrapping::None, - ownership: OutputOwnership::Mixed, - response_ty: AssociatedInnerType::Typed(syn::Type::Tuple(response_ty_tuple)), - output_ty: AssociatedInnerType::Typed(syn::Type::Tuple(output_ty_tuple)), + respond_kind: RespondKind::Mixed, + respond_ty: AssociatedInnerType::Typed(syn::Type::Tuple(response_ty_tuple)), + } + } + (RespondKind::Mixed, inner_ty) => { + let mixed_ty = make_mixed_inner(inner_ty, attr); + + OutputStructure { + wrapping: OutputWrapping::None, + respond_kind: RespondKind::Mixed, + respond_ty: AssociatedInnerType::Typed(mixed_ty), } } (ownership, inner_ty) => { let response_ty = AssociatedInnerType::new_static(inner_ty, &borrow_info); - let output_ty = AssociatedInnerType::new_gat(output_ty, &borrow_info, &ownership); OutputStructure { wrapping: OutputWrapping::None, - ownership, - response_ty, - output_ty, + respond_kind: ownership, + respond_ty: response_ty, + } + } + } +} + +fn make_mixed_inner(ty: syn::Type, attr: &Attr) -> syn::Type { + match ty { + syn::Type::Path(mut path) => { + for segment in path.path.segments.iter_mut() { + if let PathArguments::AngleBracketed(angle) = &mut segment.arguments { + for generic_arg in &mut angle.args { + if let syn::GenericArgument::Type(ty) = generic_arg { + let mixed = make_mixed(ty.clone(), attr); + *ty = mixed; + } + } + } + } + + syn::Type::Path(path) + } + ty => ty, + } +} + +fn make_mixed(ty: syn::Type, attr: &Attr) -> syn::Type { + let prefix = &attr.prefix; + match ty { + syn::Type::Reference(reference) => { + let elem = reference.elem; + + if reference.mutability.is_some() { + panic!("TODO: Mutable references in tuples"); + } + + parse_quote! { + #prefix::respond::Lent<#elem> + } + } + owned => { + parse_quote! { + #prefix::respond::Owned<#owned> } } } @@ -271,20 +268,20 @@ fn determine_associated_future_structure( fn determine_reference_ownership( sig: &syn::Signature, type_reference: &syn::TypeReference, -) -> OutputOwnership { +) -> RespondKind { if let Some(lifetime) = type_reference.lifetime.as_ref() { match lifetime.ident.to_string().as_ref() { - "static" => OutputOwnership::StaticReference, + "static" => RespondKind::StaticReference, _ => match find_param_lifetime(sig, &lifetime.ident) { Some(index) => match index { - 0 => OutputOwnership::SelfReference, - _ => OutputOwnership::ParamReference, + 0 => RespondKind::SelfReference, + _ => RespondKind::ParamReference, }, - None => OutputOwnership::SelfReference, + None => RespondKind::SelfReference, }, } } else { - OutputOwnership::SelfReference + RespondKind::SelfReference } } @@ -317,7 +314,6 @@ fn find_param_lifetime(sig: &syn::Signature, lifetime_ident: &syn::Ident) -> Opt enum AssociatedInnerType { Unit, Typed(syn::Type), - SameAsResponse, } impl AssociatedInnerType { @@ -330,47 +326,6 @@ impl AssociatedInnerType { Self::Typed(inner_type) } - fn new_gat( - mut inner_type: syn::Type, - borrow_info: &BorrowInfo, - ownership: &OutputOwnership, - ) -> Self { - if borrow_info.has_nonstatic_lifetime { - match ownership { - OutputOwnership::Owned => Self::new_static(inner_type, borrow_info), - _ => { - let mut needs_lifetime_gat = false; - - rename_lifetimes(&mut inner_type, &mut |lifetime| match lifetime { - Some(lifetime) => { - if lifetime.ident == "static" { - None - } else if borrow_info.equals_self_lifetime(lifetime) { - needs_lifetime_gat = true; - Some("'u") - } else { - Some("'static") - } - } - None => { - needs_lifetime_gat = true; - Some("'u") - } - }); - add_dyn_static_bound(&mut inner_type); - - if needs_lifetime_gat { - Self::Typed(inner_type) - } else { - Self::SameAsResponse - } - } - } - } else { - Self::SameAsResponse - } - } - fn self_type_to_unimock(&self, trait_info: &TraitInfo, attr: &Attr) -> Self { match self { Self::Typed(ty) => Self::Typed(self_type_to_unimock(ty.clone(), trait_info, attr)), @@ -398,15 +353,6 @@ struct BorrowInfo { has_undeclared_lifetime: bool, } -impl BorrowInfo { - fn equals_self_lifetime(&self, lifetime: &syn::Lifetime) -> bool { - match &self.self_lifetime_ident { - Some(ident) => lifetime.ident == ident, - None => false, - } - } -} - impl<'s> ReturnTypeAnalyzer<'s> { fn analyze_borrows(sig: &'s syn::Signature, ty: &mut syn::Type) -> BorrowInfo { let mut analyzer = Self {