5

I am writing a Rust application that handles JSON messages from a TypeScript client with a public interface. I have written some code using serde_derive and it works well, but I can't figure out how to implement dictionaries; e.g.:

{
  "foo" : { "data" : 42 },
  "bar" : { "data" : 1337 }
}

Here the keys are the strings "foo" and "bar" and the dictionary's values follow this schema:

use serde_derive;
use serde_json::Number;

#[derive(Serialize, Deserialize)]
struct DictionaryValue {
    data: Number,
}

I am looking to access the JSON data in this manner:

#[derive(Serialize, Deserialize)]
struct Dictionary {
    key: String,
    value: DictionaryValue,
}

How can I (de)serialize my JSON data into/from Dictionary using Serde?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Filippo Costa
  • 488
  • 7
  • 25
  • You must use a [hashmap](https://doc.rust-lang.org/std/collections/struct.HashMap.html) – Stargateur Apr 08 '18 at 12:56
  • 1
    @Stargateur No, any associative container like [`BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html) can be used. You can even implement one on your own. See the docs [here](https://serde.rs/impl-serialize.html#serializing-a-sequence-or-map) and [here](https://serde.rs/impl-deserialize.html). – Tim Diekmann Apr 08 '18 at 15:27

1 Answers1

10

You have a logic error in your code. The structure in your JSON file describes an associative array but your Dictionary does not support multiple key-value-pairs. As Stargateur stated in the comments, you may use HashMap as Serde has Serialize and Deserialize implementations for HashMap.

Instead of using a single key-value-pair, you can rewrite your Dictionary as

type Dictionary = HashMap<String, DictionaryValue>;

and you can retrieve the data for example by

let dict: Dictionary = serde_json::from_str(json_string).unwrap();

If you now want to wrap everything in a Dictionary-struct it will look like this:

#[derive(Serialize, Deserialize)]
struct Dictionary {
    inner: HashMap<String, DictionaryValue>,
}

The problem is, that serde_json now expects

{
  "inner": {
    "foo" : { "data" : 42 },
    "bar" : { "data" : 1337 }
  }
}

To get rid of this, you can add the serde(flatten) attribute to Dictionary:

#[derive(Serialize, Deserialize, Debug)]
struct Dictionary {
    #[serde(flatten)]
    inner: HashMap<String, DictionaryValue>,
}

If HashMap or any BTreeMap from std does not fit your needs, you can also implement your Dictionary on your own. See the docs here and here for more details.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Tim Diekmann
  • 7,755
  • 11
  • 41
  • 69