Question about map with differently-typed values


#1

Hey all,

I’m getting started with learning Rust and have spent the past couple weeks reading various Rust guides, docs, and information, and getting started on writing some simple little apps here and there.

One thing I thought would be a good learning exercise is reimplementing something I wrote in Go into Rust, which involves storing user-configurable information into PostgreSQL (using a JSONB column to store the user-configured data). This would allow them to store data somewhat like:

{
  "demographics": {
    "name": "John Doe",
    "dob": "1970-01-01",
    "active": true
  },
  "address": {
    "street": "123 Fake St",
    "city": "Faketown",
    "state": "FL",
    "zip": "12345-1234"
  }
}

(there’s a whole web UI, and a bunch of other stuff going with it, but I wanted to start with the data storage for now).

Anyhow, as I was working on this, I realized I don’t know how to store data in Rust in this fashion. I see that there is a module available that seems to provide this functionality, but since it’s from a while ago and I know Rust was under pretty active change until recently, I wasn’t sure if there was a more standard way to do this (like, in the standard library).

I like the idea of Rust quite a bit, and it seems like this probably isn’t a big deal, I’m just probably looking at it the wrong way.

Any tips or advice is appreciated!


#2

In Rust this would be stored in a struct, not a map. Something like this.

Structs are explained here and serialization of structs (which is like Go’s “marshalling”) is explained here.

#[derive(Serialize)]
struct Person {
    demographics: Demographics,
    address: Address,
}

#[derive(Serialize)]
struct Demographics {
    name: String,
    dob: String,
    active: bool,
}

#[derive(Serialize)]
struct Address {
    street: String,
    city: String,
    state: String,
    zip: String,
}

#3

Thanks for the reply!

I think I haven’t been 100% clear. The configuration of fields is determined at runtime rather than compilation time, so people would create field section records (analogous to demographics and address in this example) and fields (for the fields within the field section).

That’s why I was looking at maps initially.

Thanks again for the assistance, though, and sorry if I wasn’t clear initially.


#4

Oh in that case - you want serde_json::Value. See this part of the docs.

extern crate serde;

#[macro_use]
extern crate serde_json;

fn main() {
    let mut map = serde_json::Map::new();
    map.insert("demographics".to_owned(), json!({
      "name": "John Doe",
      "dob": "1970-01-01",
      "active": true
    }));
    map.insert("address".to_owned(), json!({
      "street": "123 Fake St",
      "city": "Faketown",
      "state": "FL",
      "zip": "12345-1234"
    }));
    println!("{:#?}", map);
    println!("{}", serde_json::to_string_pretty(&map).unwrap());
}

#5

Thanks, I think this gets me going in the right direction! I was aware of serde and serde_json, but I must have missed this end of it.