Trying to use Traits constraints (with tower) correctly?

Hi, having some lack of understanding on traits constraints

use std::future::Future;
use std::pin::Pin;
use tower::filter::{AsyncPredicate, AsyncFilterLayer};
use tower::{BoxError, Service, ServiceBuilder, ServiceExt};

#[derive(Debug, Clone)]
struct MyFilterPredicate { val: u32, }

impl AsyncPredicate<u32> for MyFilterPredicate {
    type Future = Pin<Box<dyn Future<Output=Result<Self::Request, BoxError>>>>;
    type Request = u32;

    fn check(&mut self, request: u32) -> Self::Future {
        Box::pin( async move { Ok(request) })
    }
}

pub struct Builder<U> { predicate: U, }

impl<U> Builder<U>
{
    pub fn new(predicate: U) -> Self { Self { predicate } }

    pub fn build(&mut self ) -> impl Service<u32, Response=u32, Error=BoxError> + '_
    where U: Clone + AsyncPredicate<u32>
    {
        //  (A) - This compiles nicely
        let filter_layer = AsyncFilterLayer::new( MyFilterPredicate{ val: 3});

        //  (B) - This will not compile and generates the errors below
        let filter_layer = AsyncFilterLayer::new( self.predicate.clone() );

        let mut svc = ServiceBuilder::new();
        let mut svc = svc.layer(filter_layer);
        let svc = svc.service_fn(dummy);
        svc
    }
}

async fn dummy(req: u32) -> Result<u32, BoxError> { Ok(req) }
error[E0631]: type mismatch in function arguments
  --> src/tryfilter7.rs:30:33
   |
30 |     pub fn build(&mut self ) -> impl Service<u32, Response=Result<u32, BoxError>, Error=BoxError> + '_
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected signature of `fn(<U as AsyncPredicate<u32>>::Request) -> _`
...
44 | async fn dummy(req: u32) -> Result<u32, BoxError> {
   | ------------------------------------------------- found signature of `fn(u32) -> _`
   |
   = note: required because of the requirements on the impl of `Service<<U as AsyncPredicate<u32>>::Request>` for `ServiceFn<fn(u32) -> impl std::future::Future {dummy}>`
   = note: 1 redundant requirements hidden
   = note: required because of the requirements on the impl of `Service<u32>` for `AsyncFilter<ServiceFn<fn(u32) -> impl std::future::Future {dummy}>, U>`

there are two variants of the filter_layer -
(A) by directly constructing MyFilterPredicate and compiles nicely,
(B) uses the member of Builder (predicate: U) and doesn't compiles.
I think both should be equivalent, since in the fn build() i added the trait constraints?
Obviously, i don't understand something or i am missing something. What is the difference and why does (B) not compile?

You’re missing the specification of the “Request” type in your trait bounds.

The compiler knows that MyFilterPredicate::Request is u32, that’s why (A) works.

It complains about a mismatch between

fn(<U as AsyncPredicate<u32>>::Request) -> _

and

fn(u32) -> _

The problem is: It doesn’t know if U::Request is u32 or something else.

You can fix the problem by changing the trait bound

U: Clone + AsyncPredicate<u32>

to

U: Clone + AsyncPredicate<u32, Request = u32>

thus requiring that U::Request is u32, too, making (B) work as-well.

Hi steffahn,

Thanks, it compiles. What sort of clue do you look for with this sort of errors?

Thanks

As I’ve explained, the error message mentions

in its error message

error[…]: type mismatch […]
expected signature of `fn(<U as AsyncPredicate<u32>>::Request) -> _`
found signature of `fn(u32) -> _`

This type mismatch can clearly be resolved if <U as AsyncPredicate<u32>>::Request and u32 were the same type.

But <U as AsyncPredicate<u32>>::Request is determined by the AsyncPredicate<u32> implementation of U, then looking at your bound

U: Clone + AsyncPredicate<u32>

it becomes clear that the Request type is not further specified. Which explains the type mismatch, and how to fix it.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.