How to initialize a Vec from a subset of an array? - rust

I have a fixed size u8 array of size 2048, which gets filled from a network data of varying lengths. I need to copy this data to a Vec of u8 of size equal to received length.
This is how I used to do in C++:
char buff[2048];
ssize_t data_len = recvfrom(socket, buff, sizeof(buff), 0, nullptr, nullptr);
std::vector<char> vec_buff(buff, buff + data_len)
I know Vec<T> impls From<[T; N]> and it can be created from an array by using the From::from() method, but this takes the entire size of 2048 but I want only data_len bytes.

A simple
let vec = buff[..data_len].to_vec();
will do if your type is Clone.
buff[..data_len] takes a slice of the first data_len elements, to_vec then turns that slice into a Vec
If it isn't you can use a variation of #Emoun s answer:
let vec = buff.into_iter().take(data_len).collect::<Vec<_>>();

You could use Iterator::take:
let array: [u8;2048] = ..;
let data_vec: Vec<_> = array.iter().cloned().take(data_len).collect();

Related

Copy a slice of i32 pixels into an [u8] slice

How to copy a row of pixels in an i32 slice into an existing slice of pixels in an [u8] slice ?
Both slices are in the same memory layout (i.e. RGBA) but I don't know the unsafe syntax to copy one efficiently into the other. In C it would just be a memcpy().
You can flat_map the byte representation of each i32 into a Vec<u8>:
fn main() {
let pixels: &[i32] = &[-16776961, 16711935, 65535, -1];
let bytes: Vec<u8> = pixels
.iter()
.flat_map(|e| e.to_ne_bytes())
.collect();
println!("{bytes:?}");
}
There are different ways to handle the endianess of the system, I left to_ne_bytes to preserve the native order, but there are also to_le_bytes and to_be_bytes if that is something that needs to be controlled.
Alternatively, if you know the size of your pixel buffer ahead of time, you can use an unsafe transmute:
const BUF_LEN: usize = 4; // this is your buffer length
fn main() {
let pixels: [i32; BUF_LEN] = [-16776961, 16711935, 65535, -1];
let bytes = unsafe {
std::mem::transmute::<[i32; BUF_LEN], [u8; BUF_LEN * 4]>(pixels)
};
println!("{bytes:?}");
}
Assuming that you in fact do not need any byte reordering, the bytemuck library is the tool to use here, as it allows you to write the i32 to u8 reinterpretation without needing to consider safety (because bytemuck has checked it for you).
Specifically, bytemuck::cast_slice() will allow converting &[i32] to &[u8].
(In general, the function may panic if there is an alignment or size problem, but there never can be such a problem when converting to u8 or any other one-byte type.)

Convert array (or vector) of u16 (or u32, u64) to array of u8

I have no problem to do it for u16 to u8 using bit shifts and cast but how could I do it with an array of u16? Even ideally I would prefer to convert directly from vec to [u8]. What would be the most elegant way to do it?
&my_vector[..] // my vector converted to [u16] but I need [u8]
Was able to make it work thanks to #Aplet123 insight:
From Vector to bytes array
From Vec to [u8]
let mut my_u16_vec : Vec<u16> = Vec::new();
let my_u8_array = my_u16_vec.align_to::<u8>().1;
From bytes array back to Vector
From [u8] to Vec
let n = my_u16_vec.len() * 2;
let my_u16_vec_bis:Vec<u16> = (my_u8_array[..n].align_to::<u16>().1).to_vec();
Getting the bytes right
And then reverse bytes as values are written reversely in memory due to endianness:
for e in my_u16_vec_bis:Vec.iter() {
let value = e >> 8 | (e & 0xff) << 8;
}

How to fill a [u8] array with a repeated u16 value? [duplicate]

This question already has answers here:
How to slice a large Vec<i32> as &[u8]?
(2 answers)
What is the correct way to write `Vec<u16>` content to a file?
(2 answers)
How to convert vector of integers to and from bytes? [duplicate]
(2 answers)
Closed 1 year ago.
I am looking to build an array that will be copied into RAM and sent to an LCD driver. I would like to be able to pass in a color value (color: u16) and use it to populate the array. Note that I am using #![no_std] as this is intended for an embedded application.
The obvious simple approach would be as follows:
let mut block: [u8;256] = [0; 256];
for i in (0..block.len()).step_by(2) {
block[i] = ((color && 0xFF00) >> 8) as u8;
block[i+1] = (color && 0xFF) as u8;
}
As more of my personal experience comes from C, I wondered if there were any better solutions using type casting and conversion. For example, using Rust to initialize a u16 array and cast as a u8 array:
let block_u16: [u16; 128] = [color; 128]
let block_u8 = block_u16 as [u8; 256];
For reference, the target function prototype is:
spi::setup_block(block: &[u8]);
You could go the unsafe route via transmute, but I would not recommend it. I would not vouch for a C-style version to do the same on a little and big-endian machine.
Personally I would take the chunk iterator over the slice.
let color_bytes = color.to_le_bytes();
for word in block.chunks_exact_mut(2) {
word[0] = color_bytes[0];
word[1] = color_bytes[1];
}
You could use something like your second approach (casting the u16 array to a u8 pointer).
let color: u16 = 0x0102;
let mut block: [ u16; 128 ] = [ color; 128 ];
let mut block = unsafe {
core::slice::from_raw_parts_mut( block.as_mut_ptr( ) as *mut u8, block.len( ) * 2 )
};
Beware of endianness with this solution, it might not do what you want on your target architecture.
for chunk in block.chunks_exact_mut(2) {
chunk.copy_from_slice(&color.to_be_bytes());
}

Bitwise operations, comparing a u32 with a byte array

Lets say I have the value 1025 as a byte array and the value 1030 as usize. How would I go about comparing if the byte array is bigger, lesser or equal without deserializing it?
I'm completely stuck, I assume the easisest way is to get the biggest bytes of the byte array, its position, then bitshift the u32 and see if any bits in the byte is set, if not the byte array is bigger.
In short I want to write some functions to be able to decide if a > b, a < b and a == b.
To use a code example
fn is_greater(a: &[u8], b: usize) -> bool {
// a is LE, so reverse and get the largest bytes
let c = a.iter()
.enumerate()
.rev()
.filter_map(|(i, b)| ( if *b != 0 { return Some((i, *b)); } else { None }))
.collect::<Vec<(usize, u8)>>();
for (i, be) in c {
let k = (b >> (i * 8)) & 255;
println!("{}, {}", be, k);
return be as usize > k
}
false
}
EDIT: Should have clarified, the byte array can be any integer, unsigned integer or float. Simply any integer bincode::serialize can serialize.
I also had in mind to avoid converting the byte array, comparison is supposed to be used on 100000 of byte arrays, so I assume bit operations is the preferred way.
No need for all those extra steps. The basic problem is to know if the integer encoded in the byte-array is little endian, big endian or native endian. Knowing that, you can use usize::from_??_bytes to convert a fixed-size array to an integer; use the TryFrom-trait to get the fixed-size array from the slice.
fn is_greater(b: &[u8], v: usize) -> Result<bool, std::array::TryFromSliceError> {
use std::convert::TryFrom;
Ok(usize::from_le_bytes(<[u8; 8]>::try_from(b)?) > v)
}
This function will return an error if the byte-slice is smaller than 8 bytes, in which case there is no way to construct a usize; you can also convert to u32 or even u16, upcast that to usize and then do the comparison. Also notice that this example uses from_le_bytes, assuming the bytes-slice contains an integer encoded as little endian.

How do I reference a variable used in an unsafe block?

I'm trying to read 4 bytes from a socket and then transmute those bytes into a single u32.
let mut length: u32 = 0;
// Transmute 4 byte array into u32
unsafe {
let length = mem::transmute::<[u8; 4], u32>(buf); // buf is the 4 item array of u8 that the socket was read into
println!("1: {:}", length);
}
println!("Length: {:}", length);
However, length has the original value of 0 once outside of the unsafe block. How can I get around this?
In the inner block, you're not assigning a new value to the outer length binding, you are shadowing it by defining a new length binding.
I believe that in a simple code snippet such as this (where the outer mutable variable isn't reassigned) normally there should be a compiler warning along the lines of:
warning: variable does not need to be mutable
In any case, since you have declared an outer mutable binding, all you have to do to re-assign the original variable is drop the keyword let in the unsafe block.
Additionally, as pointed out in the comments:
There's no need to initialize this particular binding with a value, because that value is always going to be replaced before it is ever used.
If you aren't really re-assigning that variable later on (in code not shown in your question), then it doesn't even need to be mutable. Mutability doesn't force you to initialize the variable at the point of its declaration in the source code.
So this should suffice:
let length: u32; // or mut
unsafe {
length = mem::transmute::<[u8; 4], u32>(buf);
println!("1: {:}", length);
}
println!("Length: {:}", length);
Note (in addition to Theodoros' answer) that unsafe block is an expression, so you can do this:
let buf = [1u8, 2, 3, 4];
// Transmute 4 byte array into u32
let length = unsafe {
let length = std::mem::transmute::<[u8; 4], u32>(buf); // buf is the 4 item array of u8 that the socket was read into
println!("1: {:}", length);
length
};
println!("Length: {:}", length);
Or in short:
let length = unsafe {std::mem::transmute::<[u8; 4], u32>(buf)};

Resources