Search code examples
rustserialization

Serde Bytes unable to serialize / deserialize


I've decided to try out serde for network packet serialization, but it's a pain.

I've been unable to serialize an Enum at all, and I keep getting errors. I can't find a working example online either, there are none in the doc nor in the repo.

That's why I'm looking for :

use serde::{Serialize, Deserialize};

use super::{ClientMessage, ServerMessage};

/// The different messages that can be sent from the client to the lobby.
#[derive(Debug, Serialize, Deserialize)]
pub enum ClientToLobbyMessage {
    Quit,
    CreateRoom,
    JoinRoom(RoomId),
}

impl ClientMessage for ClientToLobbyMessage {
    fn from_bytes(bytes: &[u8]) -> Option<ClientToLobbyMessage> {
        serde_bytes::deserialize(bytes).ok()
    }
}

This gives a compile-time error : the trait bound ClientToLobbyMessage: serde_bytes::Deserialize<'_> is not satisfied.

Adding the the #[serde(with = "serde_bytes")] above the enum fields won't work either:

use serde::{Serialize, Deserialize};

use super::{ClientMessage, ServerMessage};

/// The different messages that can be sent from the client to the lobby.
#[derive(Debug, Serialize, Deserialize)]
pub enum ClientToLobbyMessage {
    #[serde(with = "serde_bytes")]
    Quit,
    #[serde(with = "serde_bytes")]
    CreateRoom,
    #[serde(with = "serde_bytes")]
    JoinRoom(RoomId),
}

This gives an error on the derive macros: this function takes 2 arguments but 1 argument was supplied on the Serialize, and the trait bound (): serde_bytes::Deserialize<'_> is not satisfied for the Deserialize.

Finally, I can't find derive macros in the serde_bytes package, as use serde_bytes::{Serialize, Deserialize}; states : Serialize is imported here, but it is only a trait, without a derive macro.

The Cargo.toml file looks like :

[dependencies]
serde = { version = "1.0.178", features = ["derive"] }
serde_bytes = "0.11.12"

And any try to add features to serde_bytes like I did with serde resulted in: failed to select a version for serde_bytes which could resolve this conflict error.

I really hope I'm missing something obvious here, but I'm kinda desappointed as I heard that serde was super easy to use.


Solution

  • As your example is incomplete, I will assume your example is:

    use serde::{Deserialize, Serialize};
    
    trait ClientMessage: Sized {
        fn from_bytes(bytes: &[u8]) -> Option<Self>;
    }
    
    /// The different messages that can be sent from the client to the lobby.
    #[derive(Debug, Serialize, Deserialize)]
    pub enum ClientToLobbyMessage {
        Quit,
        CreateRoom,
        JoinRoom(i32),
    }
    
    impl ClientMessage for ClientToLobbyMessage {
        fn from_bytes(bytes: &[u8]) -> Option<ClientToLobbyMessage> {
            serde_bytes::deserialize(bytes).ok()
        }
    }
    

    Which produces this monstrousity of an error message:

    error[E0277]: the trait bound `&[u8]: Deserializer<'_>` is not satisfied
       --> src\lib.rs:17:34
        |
    17  |         serde_bytes::deserialize(bytes).ok()
        |         ------------------------ ^^^^^ the trait `Deserializer<'_>` is not implemented for `&[u8]`
        |         |
        |         required by a bound introduced by this call
        |
        = help: the following other types implement trait `Deserializer<'de>`:
                  UnitDeserializer<E>
                  U32Deserializer<E>
                  _::_serde::de::value::StrDeserializer<'a, E>
                  _::_serde::de::value::BorrowedStrDeserializer<'de, E>
                  StringDeserializer<E>
                  CowStrDeserializer<'a, E>
                  BytesDeserializer<'a, E>
                  BorrowedBytesDeserializer<'de, E>
                and 25 others
    note: required by a bound in `serde_bytes::deserialize`
       --> C:\Users\Finomnis\.cargo\registry\src\index.crates.io-6f17d22bba15001f\serde_bytes-0.11.12\src\lib.rs:110:8
        |
    107 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
        |        ----------- required by a bound in this function
    ...
    110 |     D: Deserializer<'de>,
        |        ^^^^^^^^^^^^^^^^^ required by this bound in `deserialize`
    
    error[E0277]: the trait bound `&[u8]: Deserializer<'_>` is not satisfied
      --> src\lib.rs:17:9
       |
    17 |         serde_bytes::deserialize(bytes).ok()
       |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Deserializer<'_>` is not implemented for `&[u8]`
       |
       = help: the following other types implement trait `Deserializer<'de>`:
                 UnitDeserializer<E>
                 U32Deserializer<E>
                 _::_serde::de::value::StrDeserializer<'a, E>
                 _::_serde::de::value::BorrowedStrDeserializer<'de, E>
                 StringDeserializer<E>
                 CowStrDeserializer<'a, E>
                 BytesDeserializer<'a, E>
                 BorrowedBytesDeserializer<'de, E>
               and 25 others
    
    error[E0277]: the trait bound `ClientToLobbyMessage: serde_bytes::Deserialize<'_>` is not satisfied
       --> src\lib.rs:17:9
        |
    17  |         serde_bytes::deserialize(bytes).ok()
        |         ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `serde_bytes::Deserialize<'_>` is not implemented for `ClientToLobbyMessage`
        |
        = help: the following other types implement trait `serde_bytes::Deserialize<'de>`:
                  Box<serde_bytes::Bytes>
                  Box<[u8]>
                  serde_bytes::ByteBuf
                  Cow<'a, [u8]>
                  Cow<'a, serde_bytes::Bytes>
                  Vec<u8>
                  std::option::Option<T>
                  &'a [u8]
                  &'a serde_bytes::Bytes
    note: required by a bound in `serde_bytes::deserialize`
       --> C:\Users\Finomnis\.cargo\registry\src\index.crates.io-6f17d22bba15001f\serde_bytes-0.11.12\src\lib.rs:109:8
        |
    107 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
        |        ----------- required by a bound in this function
    108 | where
    109 |     T: Deserialize<'de>,
        |        ^^^^^^^^^^^^^^^^ required by this bound in `deserialize`
    
    error[E0277]: the trait bound `&[u8]: Deserializer<'_>` is not satisfied
      --> src\lib.rs:17:9
       |
    17 |         serde_bytes::deserialize(bytes).ok()
       |         ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Deserializer<'_>` is not implemented for `&[u8]`
       |
       = help: the following other types implement trait `Deserializer<'de>`:
                 UnitDeserializer<E>
                 U32Deserializer<E>
                 _::_serde::de::value::StrDeserializer<'a, E>
                 _::_serde::de::value::BorrowedStrDeserializer<'de, E>
                 StringDeserializer<E>
                 CowStrDeserializer<'a, E>
                 BytesDeserializer<'a, E>
                 BorrowedBytesDeserializer<'de, E>
               and 25 others
    

    Your mistake is that you use serde_bytes as if it were a data format, which it is not. It seems to be a helper library for serde for handling byte array types.

    As suggested by @kmdreko, you could use the bincode format instead. This one is an actual encoding.

    Like this:

    use serde::{Deserialize, Serialize};
    
    trait ClientMessage: Sized {
        fn from_bytes(bytes: &[u8]) -> Option<Self>;
    }
    
    /// The different messages that can be sent from the client to the lobby.
    #[derive(Debug, Serialize, Deserialize)]
    pub enum ClientToLobbyMessage {
        Quit,
        CreateRoom,
        JoinRoom(i32),
    }
    
    impl ClientMessage for ClientToLobbyMessage {
        fn from_bytes(bytes: &[u8]) -> Option<ClientToLobbyMessage> {
            bincode::deserialize(bytes).ok()
        }
    }