4

I want to use Serde to serialize a data structure that is generic.

The users of my library should be able to provide their own structure that implements Serialize and Deserialize. I should be able to get back the original type information for the value that they serialized the data with.

How would I go about doing this?

I have tried something like this:

#[derive(Serialize, Deserialize)]
struct Message<V> {
    key: Key,
    value: V,
}

I want to get back the type of V after I deserialize the data.

Is this the way to do it or am I way off track?

I want the user to be able to extend the possible values/types. I want the behavior of enums, but flexibility for the user to add their own structs as possible candidates. Similar to this code but they all need unique ids.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
drpytho
  • 125
  • 2
  • 10
  • You might want to take a look at https://serde.rs/attr-bound.html – Søren Mortensen Mar 29 '18 at 10:55
  • @SørenMortensen I think it's kind of similar to what I'm after but I want the user to provide the de-serialize for the value and the possibility to pass different types of my generic. – drpytho Mar 29 '18 at 17:46
  • @SørenMortensen, or maybe better than I tough initially. But can it keep track of what type I used? Or do I need to tell rust what types like this `Outer` or can they be inferred? – drpytho Mar 29 '18 at 17:58
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/167836/discussion-between-drpytho-and-shepmaster). – drpytho Mar 29 '18 at 19:24
  • Does [How do I deserialize into trait, not a concrete type?](https://stackoverflow.com/q/42392935/155423) or [How can deserialization of polymorphic trait objects be added in Rust if at all?](https://stackoverflow.com/q/44231020/155423) provide information / answer your question? – Shepmaster Mar 29 '18 at 20:14
  • Close. That was what I first thought of, but I want the user to be able to extend the values/types possible. I want the behavior of enums, but flexibility for the user to add their own structs as possible candidates. Similar to [this code](https://github.com/jaysonsantos/bmemcached-rs/blob/ea627ee3456f73d39c7097b1f1647039bc74f27f/src/protocol.rs) but they all need unique *ids*. – drpytho Mar 29 '18 at 20:21

2 Answers2

3

I'm pretty sure that this is completely impossible in the general sense.

Each type is able to control its own serialization. That means that multiple types could end up serializing to the same value:

#[derive(Debug, Deserialize, Serialize)]
struct Age(i32);

#[derive(Debug, Deserialize, Serialize)]
struct Weight(i32);

fn main() {
    let a = Age(42);
    let a_str = serde_json::to_string(&a).unwrap();
    println!("{}", a_str); // 42
    let b: Weight = serde_json::from_str(&a_str).unwrap();
    println!("{:?}", b);
}

You could try to build up markers inside the serialized data that identify the type, but ultimately the same problem occurs: there's always the possibility for conflicts.

Even more fundamentally, such a concept isn't valid in Rust where each type has to have a known size at compile time. There's no way to deserialize into a variable of unknown size.

Equally fundamentally, what type would you provide for the generic V? You can't "forget" to specify all generic types when you compile your code.

Because of this, usually such a thing doesn't even come up. If the user calls your serialization code with a concrete type, they can call your deserialization code with the same concrete type.

I want the behavior of enums, but flexibility for the user to add their own structs.

That sounds like a trait object.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
0

the best way of implementing such a think would be to restrict the type of V, then use the structs name as a means of identifying the type+string for module maybe.

Example

pub struct Message<V: Serialize + Deserialize> {
     key: keytype,
     value: V,
     crate_path: String
}

then use something like sha to generate a hash for the struct name, Deserialize to check the struct name.