2

I am trying to implement an advanced serialization/deserialization scheme for a particular struct using serde and bincode crates. To demonstrate, the following code works:

use serde::{Serialize, Deserialize};
use bincode::{DefaultOptions, Options};

#[derive(Debug, Serialize, Deserialize)]
enum Command {
    Operation(u8),
    Element(Vec<u8>)
}

fn main() {
    let commands: Vec<Command> = vec![Command::Operation(150), Command::Operation(175), Command::Element(b"123".to_vec())];
    
    let bytes = DefaultOptions::new()
                    .with_varint_encoding()
                    .serialize(&commands).unwrap();

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

    let commands: Vec<Command> = DefaultOptions::new()
                    .with_varint_encoding()
                    .deserialize(&bytes[..]).unwrap();

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

Output:

[3, 0, 150, 0, 175, 1, 3, 49, 50, 51]
[Operation(150), Operation(175), Element([49, 50, 51])]

However, I would like to serialize the data in a more compressed format. There should be no explicit tag identifying which variant the data contains, instead I want this to be derived from the corresponding byte; if the byte is less than 100 it is an Element Vec<u8>, otherwise it is a Command u8. I tried setting #[serde(untagged)] for Command like so

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum Command {
    Operation(u8),
    Element(Vec<u8>)
}

I get the following output:

[3, 150, 175, 3, 49, 50, 51]
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: DeserializeAnyNotSupported', src/main.rs:45:46
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The first print is correct, but I am not sure how to implement the deserialization as explained above.

Kevin
  • 3,096
  • 2
  • 8
  • 37
  • 1
    You can simply implement [`Serialize`](https://serde.rs/impl-serialize.html) and `Deserialize` yourself, instead of deriving them. This gives you control over the format, even without being specific to `bincode`. – user2722968 Sep 03 '21 at 22:36
  • @user2722968 Good point, When calling [```serializer.serialize_seq(...)```](https://docs.serde.rs/serde/ser/trait.Serializer.html#tymethod.serialize_seq) Is it possible to somehow pass a lazy argument as ```len``` which is computed only when the method succeeds? The idea is that I do not know the ```len``` beforehand and I want this value to be dependent on the elements in the sequence (```Command```). – Kevin Sep 04 '21 at 10:29

0 Answers0