Closed audunhalland closed 1 year ago
A way to make it work:
fn foo<G, H>(&self, g: G) -> H
Auto-generated:
pub trait MockFoo: 'static {
type G<'i>;
type H;
}
impl<F: MockFoo> MockFn for F {
type Inputs<'i> = F::G<'i>;
type Response = Owned::<F::H>
// ....
}
Client-side:
struct MyGenericInstantiation;
impl mock_api::MockFoo for MyGenericInstantiation {
type G<'i> = &'i i32;
type H = i32;
}
mock_api::foo.with_types::<MyGenericInstantiation>().next_call(..)..
i.e. not extremely ergonomic..
That works except where most important: The impl Foo for Unimock {}
. There, the G
and H
are function-generic parameters, and there is no way to "find" which MockFoo
impl to select. For that to work, Unimock itself would need to be generic, which again would make it impossible to mock multiple traits.
One alternative could be to use something like https://docs.rs/bounded-static/latest/bounded_static/, but a PoC is needed first to prove whether feasible
I'm fairly sure this is impossible to solve.
MockFn
must outlive 'static
because of Any
and downcasting internally.MockFn
must therefore outlive 'static
, which they do if and only if their generic arguments are 'static
.
When we have:
The
MockFn
has to be implemented like this:TheMockStruct
has to "hold" the T through PhantomData, and MockFn is'static
, thusT: 'static
. But T is only used as a function argument, never owned by unimock itself, so this restriction seems a bit pointless.There has been some experimentation with how exactly the T is encoded within PhantomData (e.g. through a
fn(T)
) to avoid this static bound, but no exploitable loopholes have been found so far.Of course unimock also depends on getting the
TypeId::of::<F: MockFn>
so it has to be static.