rustborrow-checkerownership

Return owned value and reference to value


I have a Rust function, that has a fixed input type, but I can choose the return type:

fn foo(data: &[u8])

This function needs to make changes to that slice, so I created an owned value, so a Vec<u8>. I have to extract some parts of this vector into a library defined type, one which looks like this:

struct Foo<'a> {
    part1: &'a u8,
    part1: &'a u8,
    part1: &'a u8,
}

The struct does not have an owned type, and its internal types are all lifetimed. This struct can be created with a function that takes has his signature:

fn create(&'a [u8]) -> Foo<'a>

How can I return such a type? I can't just return it, as it references a local variable (the vector), which would be dropped at the end of the function. I also can't just return the both the vector and the Foo struct, as that would move the vector, and invalidate the reference to it.

If it is any help, the struct is a X509CertificationRequest from the crate x509_parser.

I have tried to convert the vector to a Pin<Box<Vec<u8>>> and borrow the data from that and return both of them, but that did not work. How would one do that?
I have read this, and this question, but I have found them to be unhelpful to my case, as they all suggest to rewrite the struct, which I cannot do.


Solution

  • You can use ouroboros to define a struct you can return which contains both the temporary vector and Foo:

    #[ouroboros::self_referencing]
    struct Return {
        vec: Vec<u8>,
        #[borrows(vec)]
        #[covariant]
        foo: Foo<'this>,
    }
    

    You can then use it similarly to this:

    fn create<'a>(arr: &'a [u8]) -> Return {
        let mut inner = arr.to_vec();
        ReturnBuilder {
            vec: inner,
            foo_builder: |vec|{
                Foo {
                    part1: &vec[0],
                    part2: &vec[1],
                    part3: &vec[2],
                }
            },
        }.build()
    }
    

    One of the answers to the questions you linked mentions this method, but I assume you overlooked that part of the answer.