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.
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()
}
}