Vec<u8> to a series of [u8; 2]

I'm back with another newbie question (so soon). I've spent the afternoon trying all sorts of things to solve this one ;).

I have one way to convert a series of u8 in a vector to u16,

n main() {
     let mut vec = Vec::<u8>::new();
     vec.push(20); vec.push(21);
     vec.push(22); vec.push(23);

     // OK

     let mut i = 0;
     let b = u16::from_be_bytes(vec[i..2].try_into().unwrap());
     i += 2;
     let b = u16::from_be_bytes(vec[i..2].try_into().unwrap());

     let t = vec.iter();

     // not so OK

     let b: &u8 = t.take(2).collect();
     let u = u16::from_be_bytes(b.try_into().unwrap());
     let b: &u8 = t.take(2).collect();
     let u = u16::from_be_bytes(b.try_into().unwrap());
}

I wanted to try the same with an iterator and avoid having to update my offset all the time.

20 |      let b: &u8 = t.take(2).collect();
   |                   ^^^^^^^^^ ------- required by a bound introduced by this call
   |                   |
   |                   value of type `&u8` cannot be built from `std::iter::Iterator<Item=&u8>`
   |
21 |      let u = u16::from_be_bytes(b.try_into().unwrap());
   |                                 ^ -------- required by a bound introduced by this call
   |                                 |
   |                                 the trait `From<&u8>` is not implemented for `[u8; 2]`

I suppose I could wrap the way which works in some kind of struct so I can just do

let u = thingy.get_u16(); // 0..2
let u = thingy.get_u16(); //2..2 

When I was reading bytes from a file, this worked really well

     let mut buf = [0; 2];
        match .file.read_exact(&mut buf) {
            Ok(_) => u16::from_be_bytes(buf),

and was hoping for something neat when reading from a Vec.

Thanks.

When you give type to a variable, that type will be used by the compiler as the target collection for the iterator .collect method. That being said, the compiler is telling you that &u8 is not a valid collection to be built from an iterator where the items are &u8.

This works, for example:

let collected: [&u8; 2] = vec.iter().take(2).collect::<Vec<_>>().try_into().unwrap();

I'd use the nightly feature array_chunks, which provides a convenient method for this task:

#![feature(array_chunks)]

fn main() {
	let vec = vec![20, 21, 22, 23];
	let chunks = vec.array_chunks::<2>();
	let result: Vec<u16> = chunks.map(|a| u16::from_be_bytes(*a)).collect();
	dbg!(result);
}
1 Like

And on stable, this is just

vec.chunks_exact(2).map(|chunk| <[u8; 2]>::try_from(chunk).unwrap())

where the panic case will be optimized away completely (tested in real-life signal processing code).

2 Likes

Of course. I wasn't proposing a solution, just highlighting what the compiler was complaining about on the OPs first post.

&[u8] implements Read.

    let mut bytes = &*vec;
    let mut buf = [0; 2];
    while bytes.read_exact(&mut buf).is_ok() {
        println!("{buf:?}");
    }
3 Likes

Thank you. I got close with : [u8; 2] at one point. The two collect() in my demo well that is not going to work at all :(.

That will only gather the first two elements, though. (That's what .take(2) does.)

Thank you. This is exactly what I need!

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.