Initialize a POD from a byte slice of fixed length

I'd like an idiomatic way to construct a Pod, repr(C) struct given a byte array (slice) of the appropriate size. Note that I'm not expecting to cast the byte array and deal with the alignment issues therein, but to copy the contents of the input array into a new Pod. My googling has been for naught; lots of questions about using bytemuck to cast things, but not for this use case.

I don't think this should even be unsafe, as I understand the qualifications for that.

#[repr(C)]
struct Pod {
    bytes: [u8; 16],
    a: i32, 
    b: i32,
    c: i32,
    d: i32
}

fn cvt(bytes: &[u8; 32]) -> Pod {
//    copy bytes into a new Pod, returning that
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0063]: missing fields `a`, `b`, `bytes` and 2 other fields in initializer of `Pod`
  --> src/lib.rs:12:5
   |
12 |     Pod {}
   |     ^^^ missing `a`, `b`, `bytes` and 2 other fields

For more information about this error, try `rustc --explain E0063`.
error: could not compile `playground` due to previous error

I think you’re looking for bytemuck::pod_read_unaligned:

use bytemuck::pod_read_unaligned;

#[derive(bytemuck::AnyBitPattern,Copy,Clone)]
#[repr(C)]
struct Pod {
    bytes: [u8; 16],
    a: i32, 
    b: i32,
    c: i32,
    d: i32
}

fn cvt(bytes: &[u8; 32]) -> Pod {
    pod_read_unaligned(bytes)
}
2 Likes

The efficient unsafe way is:

assert!(bytes.len() >= std::mem::size_of::<Pod>())
std::ptr::read_unaligned(bytes.as_ptr().cast())

A safe way is to chop bytes into appropriately-sized slices, convert the slices into arrays with try_from().unwrap() (the unwrap will be easily optimized out), and then set them field by field, using from_ne_bytes() for numeric types. If you're lucky it will all optimize out to a memcpy too.

1 Like

Okay, thanks. Digging into bytemuck, I can see that it is doing a type-pun and a copy, basically.