audunhalland / unimock

A versatile and developer-friendly trait mocking library
MIT License
71 stars 3 forks source link

Find a way to avoid `T: 'static` on generic arguments? #19

Closed audunhalland closed 1 year ago

audunhalland commented 1 year ago

When we have:

fn foo<T>(&self, arg: T);

The MockFn has to be implemented like this:

impl<T> MockFn for TheMockStruct<T>
    where T: 'static // <------
{
     type Inputs<'i> = T;
     // ...
}

TheMockStruct has to "hold" the T through PhantomData, and MockFn is 'static, thus T: '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.

audunhalland commented 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..

audunhalland commented 1 year ago

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.

audunhalland commented 1 year ago

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

audunhalland commented 1 year ago

I'm fairly sure this is impossible to solve.