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.
Answers
In Rust, you can't directly return a reference to data that is owned by the function. However, you can return an owned value that contains references to the data. One way to achieve this is by using a combination of Vec<u8>
and the Foo<'a>
struct, where Foo<'a>
contains references to the Vec<u8>
.
Here's how you can do it:
struct Foo<'a> {
part1: &'a u8,
part2: &'a u8,
part3: &'a u8,
}
fn create(data: &[u8]) -> Foo {
// Ensure the data slice has at least three elements
assert!(data.len() >= 3);
// Create a Foo struct containing references to the first three elements of the slice
Foo {
part1: &data[0],
part2: &data[1],
part3: &data[2],
}
}
fn foo(data: &[u8]) -> (Vec<u8>, Foo) {
// Make changes to the data slice
// For demonstration, let's create a Vec<u8> and fill it with some modified data
let mut modified_data = Vec::new();
for &byte in data {
// Modify each byte, for example, increment it by 1
modified_data.push(byte + 1);
}
// Create a Foo struct using the modified data
let foo = create(&modified_data);
// Return the modified data and the Foo struct
(modified_data, foo)
}
fn main() {
let data = [1, 2, 3, 4, 5];
let (modified_data, foo) = foo(&data);
// Print the modified data and the parts of the Foo struct
println!("Modified Data: {:?}", modified_data);
println!("Foo: part1={}, part2={}, part3={}", foo.part1, foo.part2, foo.part3);
}
In this example:
- The
create
function creates aFoo
struct containing references to the first three elements of the input slice. - The
foo
function modifies the input slice and then creates aFoo
struct using the modified data. - It returns a tuple containing the modified data and the
Foo
struct. - In the
main
function, you can see how to use the returned values.