Using serde for conversion

So I have my own struct Daten for which I can derive Serialize/Deserialize, and there's target struct Dict from typst (which also implements Serialize/Deserialize). I need to convert my struct into the target struct. I can do so manually, but I'm investigating if using serde is a good idea here. First, here's the (pretty trivial) code:

let d: Daten = ... // elided;
let s = serde_json::to_string(&d).unwrap();
let dd = serde_json::from_str(&s).unwrap();

Note that this works, no problem here.

  1. Do I need to go through a JSON string here? It seems pretty unneeded, an I tried understanding the documentation of Serialize/Deserialize to see how I could directly connect the two structs, but I could not figure this out. I've noted serde_transcode which seems similar to what I want to do, but backwards.
  2. There's 2 performance considerations I'd like to ask about:
    2a . First, I have an owned Daten here, and I need an owned Dict out of it. The manual conversion simply moves the contained values, which seems pretty efficient. Can I do something like this while running through serde?
    2b. If not, all "leaf values" of Daten are pretty cheap to clone. Could I make serde do that? Or does this all neccessarily go through a display representation or something?
  3. The main thing I'm interested here is avoiding implementation errors. The target Dict is pretty much a HashMap, and when I manually stick in the fields of my Daten struct, I might forget a field, or mistype the key. Using derive would make the much less error-prone. Is there another way to get this property, short of writing my own proc macro?

Thanks for any pointers.

2 Likes

Why don't you implement the From trait for Dict so that you can build one from an instance of Daten?

1 Like

That's what I described in 3. I can do that (and mainly do so for now) manually, but it's error-prone, and I'm investigating this for the future.

Got it. The only way I could find then is what you've already described, although using serde_json::Value as the intermediary model for better performance.

The problem with doing this is that the way Serde is designed, both serialization and deserialization are driven by the data structure's serialize() and deserialize() implementations being on the stack as long as the value of that type is being processed. This is great for avoiding allocating unnecessary buffers, but means there's a fundamental conflict where only one data type (and its fields, recursively) gets to drive control flow.

This could still be done using two threads and a pipe/channel carrying the serialized data from one to the other, though. I don't know if there is any library that implements this already; I have a vague memory of seeing one, but it's not in my notes.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.