How to clone value into new variable with different lifetime?

I read a value from Redis, which returns a Vec<u8>.

Now I want to pass these bytes into a FlatBuffer function to create an object from them. Since FlatBuffers will hold on to the Vec I need to align the lifetime of the Redis returned value with the FlatBuffer object returned by my function.

But after hours of searching and trying various approaches, I am unable to convert from Vec<u8> to &'a Vec<u8> which is what I assume I’d need here.

pub fn read_product<'a>(key: &str) -> Result<Data<'a>, redis::RedisError> {

    let client = redis::Client::open("redis://127.0.0.1/")?;
    let con = client.get_connection()?;
    
    let temp_bytes: Vec<u8> = con.get(key)?;
    let lifetime_bytes: &'a Vec<u8> = ???

    let data = flatbuffers::get_root::<Data<'a>>(&lifetime_bytes);

    Ok(data)
}

Any hints would be appreciated!

Lifetimes are a way to associate input and output references which each other. In your example, there are no input references, so anything you output has to be valid for the entirety of the program. A reference to something allocated on your function’s stack frame is not that.

Two possible solutions are (1) store your data in the caller’s stack frame by passing in a &'a mut Vec<u8> and (2) return a newtype StaticData that derefs into a Data by calling flatbuffers::get_root.

Lifetimes don’t do anything (they have absolutely zero influence on compiled code, and the compiler throws them away after initial check). Lifetimes only describe what the program is doing anyway, and work like assertions.

So ignoring lifetime syntax for a second, you’re trying to take an address of a temporary variable temp_bytes, and then pass that address and return it (wrapped) from the function. That can’t possibly work, because all variables are destroyed at the end of the function, so all references from variables become invalid. So logically there’s no way for &lifetime_bytes to work, and there doesn’t exist any valid syntax for it, because the intention of the operation is not valid.

I’m not sure how flatbuffers work, but try get_root::<Data>(lifetime_bytes); giving ownership to flatbuffers.

If flatbuffers really really only supports references, then you can’t use it in this function, because flatbuffers wants a reference to a permanently-stored value, and you don’t have a place to store the temporary result somewhere where it will live longer than the function (sadly, you can’t return both Vec and flatbuffers referencing it due to self-referential struct limitation in Rust).

fn read_product_data(key: &str) -> Result<Vec<u8>, redis::RedisError> {…}
fn get_product(data: &[u8]) -> Result<Data, redis::RedisError> {flatbuffers::get_root(data)}

That will work, because the vec will be moved and live in the function calling these:

get_product(&read_product_data(key)?)?;

Thanks so much for the detailed explanation, fitted onto my concrete example. I guess I’ll be revisiting this many times over, as it surfaced quite some misconceptions I had.

Indeed the get_root function only accepts a reference:

fn get_root<'a, T: Follow<'a> + 'a>(data: &'a [u8]) -> T::Inner

So I went for your suggestion with 2 functions at first.

Since that parsed data needs to be converted to a domain object anyway, it’ll end up in a simply returnable struct after mapping:

let data = read_data(key)?;
let parsed_data = parse_data(&data)?;

let user = Data {
    id: parsed_data.id(),
    ...
};

That was a tough one to run into after the first few hours of exploration, but after all I really like how it makes you think about the data.