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

1.5k Views Asked by At

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]);
3

There are 3 best solutions below

2
On BEST ANSWER

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];
}
2
On

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.

1
On
for chunk in block.chunks_exact_mut(2) {
    chunk.copy_from_slice(&color.to_be_bytes());
}