11

I have the following object:

{
  "data": {
    "id": 1,
    "name": "South America",
    "countries": {
      "data": [
        {
          "id": 122,
          "name": "Brazil",
          "capital": "Brasilia"
        }
      ]
    }
  }
}

I'd like to define two structs, Continent and Country, omitting the data wrappings which don't add value.

tehAnswer
  • 960
  • 1
  • 13
  • 28

1 Answers1

8

I would implement this using a wrapper struct that can be used directly for dropping the top level of nesting as well as through a #[serde(with = "...")] attribute for eliminating levels of nesting within the deserialized data structure.


use serde::{Deserialize, Deserializer};

#[derive(Deserialize, Debug)]
struct Continent {
    id: u64,
    name: String,
    #[serde(with = "Wrapper")]
    countries: Vec<Country>,
}

#[derive(Deserialize, Debug)]
struct Country {
    id: u64,
    name: String,
    capital: String,
}

#[derive(Deserialize)]
struct Wrapper<T> {
    data: T,
}

impl<T> Wrapper<T> {
    fn deserialize<'de, D>(deserializer: D) -> Result<T, D::Error>
    where
        T: Deserialize<'de>,
        D: Deserializer<'de>,
    {
        let wrapper = <Self as Deserialize>::deserialize(deserializer)?;
        Ok(wrapper.data)
    }
}

fn main() -> serde_json::Result<()> {
    let j = r#"
        {
          "data": {
            "id": 1,
            "name": "South America",
            "countries": {
              "data": [
                {
                  "id": 122,
                  "name": "Brazil",
                  "capital": "Brasilia"
                }
              ]
            }
          }
        }"#;

    let wrapper: Wrapper<Continent> = serde_json::from_str(j)?;
    println!("{:#?}", wrapper.data);

    Ok(())
}

There are three materially different places where insignificant nesting arises:

  1. adjacent to other fields
  2. by itself at the top level
  3. by itself below the top level

All three require different approaches. #2 and #3 are observed in this question.

To solve #1, see Is it possible to flatten sub-object fields while parsing with serde_json?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
dtolnay
  • 9,621
  • 5
  • 41
  • 62
  • You've [already answered this question](https://stackoverflow.com/q/41042767/155423) — why do you believe that these questions are not duplicates? – Shepmaster Feb 12 '19 at 20:26
  • 4
    The best way to solve the use case in your link (a Deserialize impl) is not the best way to solve this use case (not a Deserialize impl). Notice that there are three materially different places where insignificant nesting arises -- adjacent to other fields (observed in your link), by itself at the top level, and by itself below the top level (both observed in this question) and they require three different approaches. – dtolnay Feb 12 '19 at 20:33
  • 1
    Do you have any suggestions on how the *questions* can be improved to better highlight these differences to increase searchability? – Shepmaster Feb 12 '19 at 20:38
  • 1
    I've edited your comment into your post; Is it correct to say that #3 is addressed via `serde(with)` and #2 is addressed via directly using `Wrapper`? – Shepmaster Feb 12 '19 at 20:42