Can I take a byte array and deserialize it into a struct?

Viewed 9547

I'm reading a series of bytes from a socket and I need to put each segment of n bytes as a item in a struct.

use std::mem;

#[derive(Debug)]
struct Things {
    x: u8,
    y: u16,
}

fn main() {
    let array = [22 as u8, 76 as u8, 34 as u8];
    let foobar: Things;
    unsafe {
        foobar = mem::transmute::<[u8; 3], Things>(array);
    }

    println!("{:?}", foobar);

}

I'm getting errors that say that foobar is 32 bits when array is 24 bits. Shouldn't foobar be 24 bits (8 + 16 = 24)?

4 Answers

I was having issues using the byteorder crate when dealing with structs that also had char arrays. I couldn't get past the compiler errors. I ended up casting like this:

#[repr(packed)]
struct Things {
    x: u8,
    y: u16,    
}

fn main() {
    let data: [u8; 3] = [0x22, 0x76, 0x34];
    
    unsafe {
        let things_p: *const Things = data.as_ptr() as *const Things;
        let things: &Things = &*things_p;
        
        println!("{:x} {:x}", things.x, things.y);
    }
}

Note that with using packed, you get this warning:

   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

If you can, change Things to behave like a C struct:

#[repr(C)]
struct Things2 {
    x: u8,
    y: u16,    
}

Then initialize data like this. Note the extra byte for alignment purposes.

let data: [u8; 4] = [0x22, 0, 0x76, 0x34];

bincode and serde can do this quit simply.

use bincode::{deserialize};
use serde::{Deserialize};

#[derive(Deserialize, Debug)]
struct Things {
    x: u8,
    y: u16,
}

fn main() {
    let array = [22 as u8, 76 as u8, 34 as u8];
    let foobar: Things = deserialize(&array).unwrap();
    println!("{:?}", foobar);
}

This also works well for serializing a struct into bytes as well.

use bincode::{serialize};
use serde::{Serialize};

#[derive(Serialize, Debug)]
struct Things {
    x: u8,
    y: u16,
}

fn main() {
    let things = Things{
        x: 22,
        y: 8780,
    };
    let baz = serialize(&things).unwrap();
    println!("{:?}", baz);

}
Related