How flatten struct | Serde

119 Views Asked by At

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?

2

There are 2 best solutions below

0
Chayim Friedman On

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.

0
Mad Physicist On

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"
     }
   ]
}