Samantha Evans
Samantha Evans

Reputation: 19

How flatten struct | Serde

I try to flatten this struct, but #[serde(flatten)] doesn't work as expected

Struct example:

#[derive(Serialize, Deserialize, Debug)]
struct App {
 version: String,
 build_date: String,
 libraries: Vec<Library>
}

#[derive(Serialize, Deserialize, Debug)]
struct Library {
 #[serde(flatten)] // give me a `panic` missing field `path`
 artifact: Artifact
}

#[derive(Serialize, Deserialize, Debug)]
struct Artifact {
 path: String,
 url: String
}

Json file which I try to deserialize:

{
  "version": "0.2a",
  "build_date": "2023/12/12",
  "libraries": [
     {
       "artifact": {
         "path": "somepath",
         "url": "someurl"
       }
     },
     {
       "artifact": {
         "path": "somepath",
         "url": "someurl"
       }
     }
   ]
}

What I'm get in result (rust struct) P.S without #[serde(flatten)] it compiles, but I'm get this:

App {
  version: "0.2a",
  build_date: "2023/12/12",
  libraries: [
    Library {
      artifact: Artifact {
        path: "somepath",
        url: "someurl",
      },
    },
  ]
}

What I'm expect from #[serde(flatten)] I want to remove Artifact parentness

App {
  version: "0.2a",
  build_date: "2023/12/12",
  libraries: [
    Library {
        path: "somepath",
        url: "someurl",
    },
  ]
}

How I can make this? #[serde(flatten)] not works for me. Maybe it's a bug? In official serde-docs example almost same with my json. But it's not working. Have any ideas how solve this issue?

Upvotes: 0

Views: 1384

Answers (2)

Mad Physicist
Mad Physicist

Reputation: 114518

Alternatively, if you want the flatten attribute to have any effect, you have to make the JSON flattened. That means that the artifact key is replaced by its contents:

{
  "version": "0.2a",
  "build_date": "2023/12/12",
  "libraries": [
     {
       "path": "somepath",
       "url": "someurl"
     },
     {
       "path": "somepath",
       "url": "someurl"
     }
   ]
}

Upvotes: 0

Chayim Friedman
Chayim Friedman

Reputation: 71525

The JSON is not flattened, so you shouldn't put #[serde(flatten)]. If you want the Debug to be flattened, you can impl it manually:

use std::fmt;

#[derive(Serialize, Deserialize, Debug)]
struct App {
    version: String,
    build_date: String,
    libraries: Vec<Library>,
}

#[derive(Serialize, Deserialize)]
struct Library {
    artifact: Artifact,
}

impl fmt::Debug for Library {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.artifact.fmt(f)
    }
}

#[derive(Serialize, Deserialize, Debug)]
struct Artifact {
    path: String,
    url: String,
}

But note that Debug is for programmer-only output, not for user-facing output.

Upvotes: 2

Related Questions