Borrowed value does not live long enough?

I have the following code:

extern crate serde;
extern crate rmp;

use std::collections::HashMap;
use std::error::Error;
use std::io::Cursor;

pub struct User {
     pub username: String,
     pub password: String,
     pub virtual_host: String
}

pub fn from_bytes(input: Vec<u8>) ->  Result<User, Box<Error>> {
    let data = &input[..];
    let (username,data2) = rmp::decode::read_str_from_slice(data)?;
    let (password,data3) = rmp::decode::read_str_from_slice(data2)?;
    let (virtual_host,_) = rmp::decode::read_str_from_slice(data3)?;
    let user = User{
        username: username.to_string().clone(),
        password: password.to_string().clone(),
        virtual_host: virtual_host.to_string().clone()
    };
    return Ok(user);
}

and the error is as follows:

   |                                                                                                              
16 |     let data = &input[..];                                                                                   
   |                 ^^^^^ borrowed value does not live long enough                                               
...                                                                                                               
26 | }                                                                                                            
   | - borrowed value only lives until here   

I have spent my entire day trying to fix this :frowning:
Any help is appreciated. (I am currently using rust 1.30)

It’s because decode_from_str's error type has a variant with a lifetime - rmp::decode::DecodeStringError - Rust - and you’re using Try (ie ? operator).

But there’s no way for your fn to satisfy that since it’s not taking any references input, just an owned Vec, and claims it returns a Box<Error>, which is short for Box<Error + 'static>.

So, you may want to either take a slice reference as input (and adjust the error type in your return type), or map their error to something that doesn’t borrow anything.

Happy to help more but on mobile and got winded in typing :slight_smile:

Yes that solved it. Thank you so much!

In simple terms, it was a return/error type mismatch, the compiler should have just said that instead of confusing me about scope. I see that there are countless other topics which have the same error each with a different cause. I don't know if the compiler could be improved to catch these scenarios but giving at least a list of hints would be useful.

If anyone else is looking to how I solved it:


pub fn from_bytes(input: Vec<u8>) ->  Result<User, Box<Error>> {
    let data = &input[..];
    let (username,data2) = decode_string(data)?;
    let (password,data3) = decode_string(data2)?;
    let (virtual_host,_) = decode_string(data3)?;
    let user = User{
        username: username.to_string().clone(),
        password: password.to_string().clone(),
        virtual_host: virtual_host.to_string().clone()
    };
    return Ok(user);
}

pub fn decode_string(data: &[u8]) -> Result<(&str, &[u8]), Box<Error>> {
    match rmp::decode::read_str_from_slice(data) {
        Ok(result) => {
            return Ok(result)
        }  ,
        Err(e) => return Err(e.to_string().into())
    }
}

Minor note on conventions, if you are using dynamic dispatch with traits i.e. std::err::Error then you should write Box<dyn Error> instead of Box<Error>, the latter is still valid, but is being deprecated and is invalid syntax in Rust 2018 see the dyn's RFC and it's tracking issue for more info.

Thanks

Will "cargo fix" be able to do refactor this on its own?
I don't even understand what the difference is, at the moment I am just stitching together code from various Rust tutorials.

I don't know, i haven't used cargo fix before.