1

I am trying to make this simplified and self-contained version of my code compile:

struct FragMsgReceiver<'a, 'b: 'a> {
    recv_dgram: &'a mut FnMut(&mut [u8]) -> Result<&'b mut [u8], ()>,
}

impl<'a, 'b> FragMsgReceiver<'a, 'b> {
    fn new(
        recv_dgram: &'a mut FnMut(&mut [u8])
            -> Result<&'b mut [u8], ()>
    ) -> Self {
        FragMsgReceiver { recv_dgram }
    }
}

fn main() {
    let recv_dgram = |buff: &mut [u8]| Ok(buff);
    let fmr = FragMsgReceiver::new(&mut recv_dgram);
}

Here is the error:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/main.rs:15:43
   |
15 |     let recv_dgram = |buff: &mut [u8]| Ok(buff);
   |                                           ^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 15:22...
  --> src/main.rs:15:22
   |
15 |     let recv_dgram = |buff: &mut [u8]| Ok(buff);
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that expression is assignable (expected &mut [u8], found &mut [u8])
  --> src/main.rs:15:43
   |
15 |     let recv_dgram = |buff: &mut [u8]| Ok(buff);
   |                                           ^^^^
note: but, the lifetime must be valid for the block suffix following statement 1 at 16:53...
  --> src/main.rs:16:53
   |
16 |       let fmr = FragMsgReceiver::new(&mut recv_dgram);
   |  _____________________________________________________^
17 | | }
   | |_^
note: ...so that variable is valid at time of its declaration
  --> src/main.rs:16:9
   |
16 |     let fmr = FragMsgReceiver::new(&mut recv_dgram);
   |         ^^^

From what I understand from the error message, the compiler doesn't understand that the buff reference (argument of recv_dgram) can actually live longer than the inner body of recv_dgram. I could be wrong though.

To give some context, I'm trying to create a struct that wraps a Rust Tokio UDP socket. To do this, I take a reference to a function recv_dgram. In my original code this function takes a buffer as argument, and returns a Future. When the Future is ready, the buffer will be filled. The Future's item also contains the address of sender and the amount of bytes that were written into the buffer.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
real
  • 639
  • 1
  • 6
  • 15
  • That's not a function; it's a closure. Is there a reason you need to have a reference to the trait object instead of just using a generic? – Shepmaster Sep 13 '17 at 12:51
  • Drop the type specifier on the closure argument to allow inference to work, then specify that the value you are passing to the closure has the same lifetime as the result, then fix the `mut` qualifier. [Completed example](https://play.rust-lang.org/?gist=5650836c790a4394e853ebc76bb84148&version=stable). – Shepmaster Sep 13 '17 at 13:01
  • @Shepmaster: Thanks! There is still something I can't solve: I want to allow 'a to outlive 'b, as recv_dgram gets various buffers and their lifetime in my opinion should not be related to 'a. When I try to remove the 'b:'a I get a compile error. ```in type `&'a mut std::ops::FnMut(&'b mut [u8]) -> &'b mut [u8] + 'a, reference has a longer lifetime than the data it references```. How can this be solved? – real Sep 13 '17 at 13:11
  • @Shepmaster: I appreciate the work you are doing by editing and marking duplicate, however I don't think that this question is a duplicate of the mentioned questions. I read those two before I posted my question here. red75prime 's answer has some information about lifetimes that I couldn't find elsewhere. – real Sep 13 '17 at 13:21
  • Thank you for the kind words. However, I don't just mark questions as duplicates, I update the duplicates with any new knowledge whenever we get it. If you check them now, both have been enhanced. This avoids future users having to navigate to *N* different questions to get all the variations of the answer. Thus, I believe they are still duplicates; but you are welcome to vote to reopen. – Shepmaster Sep 13 '17 at 13:41

1 Answers1

1

Let's start by restoring elided lifetime in your declaration

struct FragMsgReceiver<'a, 'b: 'a> {
    recv_dgram: &'a mut for<'c> FnMut(&'c mut [u8]) -> Result<&'b mut [u8], ()>,
}

This declaration means that FragMsgReceiver holds a mutable reference to a FnMut trait object which takes a mutable reference to a slice having any lifetime 'c and returns a reference with lifetime 'b: 'a.

This is not what you need. You need an FnMut which returns a reference with the same lifetime as the lifetime of the input parameter. This can be written as:

type FnTraitObject = FnMut(&mut [u8]) -> Result<&mut [u8], ()>;

struct FragMsgReceiver<'a> {
    recv_dgram: &'a mut FnTraitObject,
}

impl<'a> FragMsgReceiver<'a> {
    fn new(recv_dgram: &'a mut FnTraitObject) -> Self {
        FragMsgReceiver { recv_dgram }
    }
}

Lifetime elision does the right thing here, but the compiler still complains: "expected bound lifetime parameter, found concrete lifetime", pointing at FragMsgReceiver::new(&mut recv_dgram).

This error is caused by a limitation of Rust's type inference. We need to assist the inference by coercing the type of the closure as it was pointed out by DK.

fn constrain_handler<F>(f: F) -> F
where
    F: FnMut(&mut [u8]) -> Result<&mut [u8], ()>,
{
    f
}

// ...

let mut recv_dgram = constrain_handler(|buff| Ok(buff));

Complete code on the playground

To clarify, for<'c> means that 'c can be any lifetime and the lifetime is determined at a call site. For example, the pointer to the function fn foo(_: &u32) -> &u32 has the type for<'a> fn(&'a u32) -> &'a u32.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
red75prime
  • 3,733
  • 1
  • 16
  • 22