Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cannot transmute between types of different sizes, or dependently-sized types

Tags:

rust

I have a struct which I need to convert to byte buffer. Currently I'm using bytemuck crate to get this done, but I'm getting an error

#[derive(bytemuck::NoUninit, Clone, Copy)]
#[repr(C)]
pub struct Data {
    pub msg_id: u16,

    pub id: [u8; 128],

    pub a: f64,
    pub b: f64,
    pub c: f64,
    pub d: f64,
    pub e: f64,
    pub f: f64,
    pub g: f64,
}

fn main() {
    
}

Error

error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
 --> src/main.rs:3:12
  |
3 | pub struct Data {
  |            ^^^^
  |
  = note: source type: `Data` (1536 bits)
  = note: target type: `TypeWithoutPadding` (1488 bits)

For more information about this error, try `rustc --explain E0512`.
error: could not compile `playground` (bin "playground") due to previous error
like image 615
Harry Avatar asked Oct 25 '25 01:10

Harry


1 Answers

You have 130 bytes of data followed by a f64, which has alignment 8. 130 mod 8 = 2, so (per the repr(C) layout rules) there will be padding bytes placed between id and a. Padding bytes are always uninitialized, so they do not qualify for being bytemuck::NoUninit.

You must change your struct declaration so that it actually does not have uninitialized bytes. In some cases, you could do this by reordering the fields, but here that would leave you with padding at the end of the struct (because in Rust, a type's size is always a multiple of its alignment). Therefore, you will have to insert 6 bytes of explicit “padding”, so that the total byte size of the fields before the first f64 is a multiple of 8:

pub struct Data {
    pub msg_id: u16,
    pub _padding: [u8; 6],

    pub id: [u8; 128],

    pub a: f64,
    pub b: f64,
    pub c: f64,
    pub d: f64,
    pub e: f64,
    pub f: f64,
    pub g: f64,
}

This _padding field can be set to [0; 6] or whatever value you like; the important thing is that the language considers it to have a specific value, not be uninitialized, which is the property that bytemuck::NoUninit requires.

Of course, if you can find a use for those extra bytes, or a way to remove 2 bytes, that's even better.

like image 169
Kevin Reid Avatar answered Oct 26 '25 19:10

Kevin Reid