Matteo Monti
Matteo Monti

Reputation: 8930

Serialize / Deserialize a struct that can be represented as an array of bytes

I am working with a struct that looks more or less like this:

struct MyStruct {
   // Various fields, most of which do not implement `Serialize` / `Deserialize`
}

struct MyError; // Yes, this implements `std::error::Error`

impl MyStruct {
   fn from_bytes(bytes: [u8; 96]) -> Result<MyStruct, MyError> {
      // Creates a `MyStruct` from an array of exactly 96 bytes.
      // It returns a `MyError` upon failure.
   }

   fn to_bytes(&self) -> [u8; 96] {
      // Serializes `MyStruct` into an array of exactly 96 bytes.
   }
}

Now, I would like to have MyStruct implement serde's Serialize and Deserialize. Intuition tells me it should be simple (I literally have functions that already serialize and deserialize MyStruct), but after hours of confused trial and error I'm stuck.

What I would like to have is MyStruct implement Serialize and Deserialize and, should I call bincode::serialize(my_struct), I would like it to be represented in exactly 96 bytes (i.e., I would like to avoid paying the cost of a pointless, 8-byte header that always says "what follows is a sequence of 96 bytes": I already know that I need 96 bytes to represent MyStruct!).

Upvotes: 0

Views: 968

Answers (1)

Jakub D&#243;ka
Jakub D&#243;ka

Reputation: 2625

First part of your question can be accomplished as following:

use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
use serde_big_array::BigArray;

#[derive(Serialize, Deserialize)]
struct Wrap {
    #[serde(with = "BigArray")]
    arr: [u8; 96],
}

struct MyStruct {}

struct MyError;

impl Display for MyError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        todo!()
    }
}

impl MyStruct {
    fn from_bytes(bytes: [u8; 96]) -> Result<MyStruct, MyError> {
        todo!()
    }

    fn to_bytes(&self) -> [u8; 96] {
        todo!()
    }
}

impl serde::Serialize for MyStruct {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        Wrap {
            arr: self.to_bytes(),
        }
        .serialize(serializer)
    }
}

impl<'de> serde::Deserialize<'de> for MyStruct {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let bytes = <Wrap>::deserialize(deserializer)?;
        Self::from_bytes(bytes.arr).map_err(D::Error::custom)
    }
}

The second part is tough and depends on the format you are using with serde.

Upvotes: 1

Related Questions