Convert Vec<Vec<u8>> to &[&[u8]]

Viewed 1300

I have a function that takes some number of byte strings: &[&[u8]] but want to call it with an argument of type Vec<Vec<u8>>. Calling the function like this:

let foo: Vec<Vec<u8>> = Vec::new();
bar(&foo[..]);

converts foo to a slice but not the values it contains. Is there a way to do this conversion easily and efficiently? Or can I change the type of the function argument to avoid cases like this?

2 Answers

From a memory perspective this doesn't make much sense. To create a slice, the data being sliced must first exist in memory. However to take a slice of &[u8], you first need to have some data structure like Vec<&[u8]> to take the slice from.

In other words to do this, you need to allocate space for Vec<&[u8]> or [&[u8]; N] and fill it with slices first. This somewhat defeats the purpose of using slices since slices are meant to existing reference memory in place. Consider using &[Vec<u8>] for your function instead.

If having slices in the second layer is important or you are unable to edit the function you can do the following to convert Vec<Vec<u8>> to &[&[u8]]:

let foo: Vec<Vec<u8>> = Vec::new();

// Allocate Vec of references to slices
let tmp: Vec<&[u8]> = foo.iter().map(|x| &x[..]).collect();

// Take slice of temporary Vec
bar(&tmp[..]);

One way to handle this case without allocating an additional Vec is to use AsRef<[u8]>:

fn bar<S: AsRef<[u8]>>(args: &[S]) {
    // ...
}

Inside the function, you can use .as_ref() to convert each of the arguments to a &[u8].

(playground)

Related