Your implementation of NewResourceUser
is as such:
impl<'a> NewResourceUser<MyResourceUser<'a>> for &'a MyResource {
So &'a MyResource
only implements NewResourceUser<MyResourceUser<'a>>
-- the lifetimes have to be the same.
But the supertrait requirement on Factor
resolves like so:
for<'a, 'r> &'r MyResource: NewResourceUser<MyResourceUser<'a>>
That is, you'd have to be able to get a MyResourceUser<'a>
out of any &'r MyResource
, even though they have unrelated lifetimes. That's not possible, so that supertrait bound isn't what you want.
I think you really wanted U
to be a type constructor;[1] that is, you wish you could have
// Made up syntax/feature
trait Factory<R, U<'*>> where for <'a> &'a R: NewResourceUser<U<'a>> {
But Rust doesn't have those. Type parameters like U
must resolve down to a single type -- that means all lifetimes must resolve too. Just like U
can't represent Vec<X>
for any X
, U
can't represent MyResourceUser<'x>
for any 'x
.
If any given R
only needs to be associated with a specific type constructor like MyResourceUser<'_>
, and if object safety isn't a concern, you could make the type constructor a GAT in NewResourceUser
.
However it won't really work with the requirement to be able to choose U
...
So, maybe you do really need to emulate "type constructor generics". One way to do this is to have a trait with a GAT...
// A type constructor for NewResourceUser<impl Resource>::new_user
trait Resource {
type Ty<'a>;
}
...then implement the trait for marker types that will represent the type constructor with any lifetime...
struct MyResourceUserMarker;
impl Resource for MyResourceUserMarker {
type Ty<'a> = MyResourceUser<'a>;
}
...and use type parameters with a : Resource
bound...
trait NewResourceUser<U: Resource> {
fn new_user(&self) -> <U as Resource>::Ty<'_>;
}
trait Factory<R, U> where R: NewResourceUser<U>, U: Resource {
fn new_resource() -> R;
}
Like so:
something that is parameterized by generic lifetimes and/or traits ↩︎
Nit (or fundamental understanding adjustment): the lifetime limitation will be based on standard borrowing considerations in this scenario (
fn fru
in my playground below), i.e., the result ofr.new_user()
will borrowr
and won't be able to outliver
being moved, mutably borrowed, or destructed; the type ofr
/R
is incidental. ↩︎