Currently when you implement Deref<T> on a type A, you can use all the functions defined both by T and by the traits implemented by T.
For example you can do something like this:
use std::collections::Collection;
struct Foo(Vec<int>);
impl Deref<Vec<int>> for Foo {
fn deref(&self) -> &Vec<int> {
let &Foo(ref val) = self;
val
}
}
fn main() {
let f = Foo(Vec::new());
println!("{}", f.is_empty());
}
But let’s say you have a function that awaits an object which implements Collection. You can’t directly pass a Foo or you would get error: failed to find an implementation of trait core::collections::Collection for Foo.
The call can still be achieved by calling needs_collection(&*foo) instead of just needs_collection(&foo).
If I now implement MyCustomTrait for Foo, calling needs_mycustomtrait can be done with needs_mycustomtrait(&foo).
But what if a function requests an object which implements both Collection and MyCustomTrait? Well, currently you can’t call it with a Foo at all, even though you can call methods from both Collection and MyCustomTrait on the foo object itself.
My proposed solution
Allow directly passing a Foo to a function which awaits a Collection. More generally, objects which implement Deref<T> and/or DerefMut<T> should automatically be treated as if they implemented all the traits that T implements.
This should be recursive. If A implements Deref<T> and T implements Deref<U>, then A implements the traits of U.
Real-life motivation
The reason why I’m opening this thread is this reddit post.
The idea is to implemented a web framework. When a request is received by the server, a BaseRequestis created. Then it is turned into a WithSession<BaseRequest>, which is then turned into a WithDatabase<WithSession<BaseRequest>>, which is then turned into a WithAuthenticationAttempt<WithDatabase<WithSession<BaseRequest>>>, which is then turned into a WithAuthenticatedUser<WithAuthenticationAttempt<WithDatabase<WithSession<BaseRequest>>>>, etc.
Even when each element implements Deref for its underlying object, there is currently no way to pass an object of this type to a fn handler<R: HasDatabase + HasAuthenticatedUser + HasBasicRequest>(request: R) because of the issue explained in this thread, even though you can call methods from HasDatabase, HasAuthenticatedUser and HasBasicRequest on the object.
Of course the stack of objects depends on what the framework user needs, that’s why you need to use traits and cannot simply use a type Rq = .... To answer a static content, you only need a HasBasicRequest, but to query a user profile you need a HasDatabase + HasAuthenticatedUser + HasBasicRequest, and to handle a file upload you need a HasFileUpload.