Lifetime problems


#1

Sorry for the vague title, nothing more specific comes to my mind at the moment.

I have this piece of code that does not compile:

    impl<'a, T> Decoder for NetlinkCodec<NetlinkBuffer<T>>
        where T: From<&'a [u8]> + AsRef<[u8]>
    {
        type Item = NetlinkBuffer<T>;
        type Error = Error;
    
        fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
            let len = match NetlinkBuffer::new_checked(src.as_ref()) {
                Ok(buf) => buf.length() as usize,
                Err(Error::Truncated) => return Ok(None),
                Err(e) => panic!("Unknown error while reading packet: {}", e),
            };
            let bytes = src.split_to(len);
            
            // create a T from a slice of bytes.
            let t = T::from(&bytes);
            // `bytes` is still borrowed here :(
            // I understand _why_ but I mean to express the fact that T::from uses the reference and
            // then does not need it anymore.
            Ok(Some(NetlinkBuffer::new(t)))
        }
    }

This fails with:

  --> rtnetlink/src/codecs.rs:44:26
   |
44 |         let t = T::from(&bytes);
   |                          ^^^^^ borrowed value does not live long enough
...
49 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 29:6...
  --> rtnetlink/src/codecs.rs:29:6
   |
29 | impl<'a, T> Decoder for NetlinkCodec<NetlinkBuffer<T>>
   |      ^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
error: Could not compile `rtnetlink`.

I do understand the problem, because if T looks like this, it makes sense to not allow it:

    pub struct T<'a>(&'a[u8]);
    
    impl<'a> From<&'a [u8]> for T<'a> {
        fn from(slice: &'a [u8]) -> Self {
            T(slice)
        }
    }

But what I want to allow is this kind of implementation for T:

    pub struct T(Vec<u8>);
    
    impl<'a> From<&'a [u8]> for T {
        fn from(slice: &'a [u8]) -> Self {
            T(slice.to_vec())
        }
    }

How can I express the fact that T's lifetime should not be bound the slice lifetime it’s coming from?

FWIW here is the full code: https://github.com/little-dude/netlink/blob/650c812652a706bde8143e7cf1c8e99934ac4225/rtnetlink/src/codecs.rs#L29-L50


#2

Try T: for<'b> From<&'b [u8]> + AsRef<[u8]> instead. This way your &bytes can be an unspecified short-lived lifetime. Right now you’re forcing it to be essentially &'a bytes, which would have to outlive the function call.


#3

This way your &bytes can be an unspecified short-lived lifetime.

Thanks this is exactly what I wanted to express!

But… what the hell is this for<'b> syntax? I don’t remember ever seeing that.
I checked the nomicon and the rust book before posting here, and it’s not there as far as I can tell.


#4

I don’t know if it’s in the normal book, but it’s called HRTB in the nomicon:
https://doc.rust-lang.org/nomicon/hrtb.html


#5

I always refer people to this stackoverflow answer for a good explanation of HRTB.