Type mismatch when using lifetimes

Hi there!

I'm writing a generic - over request/return types and the path separator character - router module and have encountered issues during testing.

Unfortunately, I couldn't very much reduce it to a simpler reproduction, but I'll try to be descriptive enough so that it's not a pain for you kind souls to dig through it. It's not a large library by any means - most if it is testing code, really.

The code is available on GitHub and requires min_const_generics to build - unless of course you get rid of const SEPARATOR: char everywhere, which, in hindsight, I really should have done myself. Apologies.

So what's happening is that when I define the handler to use a &[u8] as its Request type, Rust suddenly complains about mismatched types, which, by the way, are more likely "just" mismatched lifetimes.

error[E0308]: mismatched types
   --> src\router.rs:115:57
    |
115 |     router.define(route.clone(), RouteHandler::Function(&handler));
    |                                                         ^^^^^^^^ one type is more general than the other
    |
    = note: expected enum `std::result::Result<_, Error<'_, '_, &[u8]>>`
               found enum `std::result::Result<_, Error<'_, 'request, &[u8]>>`

The test function (router.rs:108) that fails to build is this:

#[test]
  fn define() -> anyhow::Result<()> {
    let mut router = Router::<_, _, '/'>::new();

    let route = Route::parse("hello/there");
    let other_route = Route::parse("hello/where");

    router.define(route.clone(), RouteHandler::Function(&handler));

    assert_eq!(router.routes.len(), 1);

    assert!(router.get(&route).is_some());
    assert!(router.get(&other_route).is_none());

    Ok(())
  }

And handler refers to the following function (router.rs:89):

fn handler<'router, 'request>(
    params: HashMap<&'router str, &'request str>,
    request: &'request [u8],
  ) -> Result<
    'router,
    'request,
    &'request [u8],
    bool,
  > {
    if params.len() != 1 || params["subject"] != "general" {
      return Err(Error::InvalidParams(params.clone()));
    }

    match request {
      [0x42] => Ok(true),
      request => Err(Error::InvalidRequest(request)),
    }
  }

If I just replace &'request [u8] (router.rs:91 and router.rs:95) with an owned value like u8 and change [0x42] to 0x42 (as an example), the build succeeds.

I'm not sure if I'm overlooking some straightforward lifetime rule or it's a limitation of Rust, but I've exhausted all my knowledge on the topic - which really wasn't much to begin with.

I've been banging my head against a wall over this for two days now, and I feel like my mind is at a point where it's physically incapable of coming up with a new angle. Any and all help is much appreciated!

As it turns out, all I've had to do was add an extra lifetime parameter to handler (router.rs:89). This convinced Rust that what I'm doing is perfectly fine.

fn handler<'router, 'request, 'data>(
//                          ^^^^^^^ added this
    params: HashMap<&'router str, &'request str>,
    request: &'data [u8],
//             ^^^^ changed this
  ) -> Result<
    'router,
    'request,
    &'data [u8],
//    ^^^^ changed this
    bool,
  > {
    if params.len() != 1 || params["subject"] != "general" {
      return Err(Error::InvalidParams(params.clone()));
    }

    match request {
      [0x42] => Ok(true),
      request => Err(Error::InvalidRequest(request)),
    }
  }

Onto the next error, I suppose.

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.