Capnproto reader: cannot return value referencing temporary value

In the following I try to deserialize a Vec<u8> with Capnproto:

use capnp::{message::ReaderOptions, serialize_packed};
use std::io::Cursor;

fn get_reader<'a>(buffer: Vec<u8>) -> Result<Reader<'a>, CapnpError> {
    let reader = &serialize_packed::read_message(&mut Cursor::new(buffer), ReaderOptions::new())?;
    let typed_reader = reader.get_root::<Reader>()?;
    Ok(typed_reader)
}

But I get the same error every time, which is:

cannot return value referencing temporary value
returns a value referencing data owned by the current function

So far I've tried cloning both reader and typed_reader and returning reference instead of owned type.
I'm on stuck this, please help.

You're trying to return something that contains a reference to the buffer object, but buffer is destroyed when you return from the function, so that's not valid. Any amount of cloning, adding references and other stuff is not going to solve that.

Try changing the type of buffer from Vec<u8> to &'a [u8].

2 Likes

I’m not familiar with the crate in use, but it seems like your function cannot be written without changing the signature significantly. One approach that can often work in cases like this is to offer the ought-to-be-returned value to a callback instead. There’s a few different ways I can imagine writing the method here in detail, one way is e.g.

fn with_reader<F, R>(buffer: Vec<u8>, callback: F) -> Result<R, CapnpError>
where
    F: FnOnce(Reader<'_>) -> Result<R, CapnpError>,
{
    let reader = &serialize_packed::read_message(&mut Cursor::new(buffer), ReaderOptions::new())?;
    let typed_reader = reader.get_root::<Reader>()?;
    f(typed_reader)
}

(untested, so may contain minor errors)

Then the caller would need to work with a callback

let some_value = with_reader(vector, |r| {
    // use `r`
    Ok(/* return some (owned) value if you like*/)
})?;

Another option that might work for you would be to pass in some kind of storage place where to put the capnp::message::Reader<capnp::serialize::OwnedSegments>.

// expects a reference to a `None` where the reader can be stored
fn get_reader<'a>(buffer: Vec<u8>, slot: &'a mut Option<message::Reader<OwnedSegments>>) -> Result<Reader<'a>, CapnpError> {
    let reader = slot.insert(serialize_packed::read_message(&mut Cursor::new(buffer), ReaderOptions::new())?);
    let typed_reader = reader.get_root::<Reader>()?;
    Ok(typed_reader)
}

Then the caller would need to prepare a slot to store the message::Reader<…> and keep it alive while the returned Reader<'a> is in use.

let mut slot = None;
let r = get_reader(vector, &mut slot)?;
// use `r` here
2 Likes

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.