I've recently been playing around with tower, and in particular the Service
, which I've copied over verbatim below:
pub trait Service<Request> {
type Response;
type Error;
type Future: Future;
fn poll_ready(
&mut self,
cx: &mut Context<'_>
) -> Poll<Result<(), Self::Error>>;
fn call(&mut self, req: Request) -> Self::Future;
}
My problem is that I want to created a restricted version of this trait, something like the following:
pub struct MyRequest;
pub struct MyResponse;
pub struct MyErr;
pub trait MyTrait: Service<MyRequest> {
type Response: MyResponse;
type Error: MyErr;
type Future: Future;
fn poll_ready(
&mut self,
cx: &mut Context<'_>
) -> Poll<Result<(), Self::Error>>;
fn call(&mut self, req: Request) -> Self::Future;
}
The idea is that implementations of MyTrait
are restricted to a subset of what Service
can be implemented as, leading to implementations similar to the following:
pub struct Foo;
impl MyTrait for Foo {
type Future: Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;
fn poll_ready(
&mut self,
cx: &mut Context<'_>
) -> Poll<Result<(), Self::Error>> {
todo!();
}
fn call(&mut self, req: Request) -> Self::Future{
todo!();
}
}
which means that instead of writing a function like the following:
pub fn name<T>(_arg: T) -> ()
where
T: Service<
MyRequest,
Response = MyResponse,
Error = MyError,
Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>,
>
{
unimplemented!()
}
You can instead write something like:
pub fn name<T>(_arg: T) -> ()
where
T: MyTrait<Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>>
{
unimplemented!()
}
The issue is that this doesn't currently work. For one thing, it conflicts with another good idea, RFC 2532, "Associated type defaults". For another, Rust traits are specifically designed so that C++ subclass-like behavior is forbidden. I suspect that changing this would be a major breaking change as it would imply that marker traits would be required to be non-empty, so I'm not suggesting it. The problem is that I can't think of something that would work well here. Can anyone else? Or is there a reason why syntactically different versions of this would be a bad idea?