Serde deserialize to enum from json object

I have the following json value:

"value": [
  {
     "file": { "mimeType": "whatever" }
  },
  {
     "folder": { "count": 9 }
  }

I'd like to parse this directly to deserialize the following type:

#[derive(Deserialize)] 
struct RawInput {
     #[serde(alias = "file", alias = "folder")]
     file_or_folder: FileOrFolder
}

#[derive(Deserialize)] 
enum FileOrFolder {
   File: { 
          #[serde(rename = "mimeType")]
          mime_type: String 
   },
   Folder,
}

I've had success deserializing using Option<File> and Option<Folder> to capture and then process. However, it seems clumsy and doesn't capture the essence of the type: It will be one or the other; so enum.

However, when I run this I get the following error:

"... error decoding response body: unknown variant `count`, expected `file` or `folder` at line 1 column 323"

Here is the playground that replicates the error

I can't seem to get my head around how to use the json key (file or folder) to accomplish both mapping to the file_or_folder while instantiating the enum in file_or_folder: FileOrFolder.

So, the goal is to use the presence of a json object property to instantiate an enum.

Deserializing Vec<FileOrFolder> should work.

edit: Playground

1 Like

Thanks for confirming that this "base case" should be work I'll have to look upstream to better understand this issue; I'll do so starting from the playground you put together (thank you for that). The "red herring" is that I can get it to go as expected with local changes to the code.

@SabrinaJewson I updated the post to include the playground where I replicate the error. The difference is that I put the FileOrFolder in a file_or_folder property of the struct. So I have a Vec<RawFile>, not Vec<FileOrFolder>.

{
  "value": [
    {
      "file": {}
    },
    {
      "folder": {}
    }
  ]
}
// Vec of struct that hosts a property that is a enum
// which enum variant depends on presence of json key file | folder
// serde sets the `file_or_folder` value using presence of key
struct RawFile {
   id: String,
   file_or_folder: FileOrFolder
}

// not Vec of enum where enum variant depends on file or folder
// serde sets the Vec<variant> using presence of key

aside: I'm not sure either version is different in the information hosted by each; the Vec<RawFile> seems to avoid having to repeat the spec for every field in each version of the enum.

Here is a link to the solution. The answer was to use serde's flatten macro for the file_or_folder that did not exist in the raw data, but was built using a combination of fields in the raw data (per the serde docs for Pagination, where the raw data does not have the key pagination, but the values to construct Pagination).

#[derive(Debug, Deserialize)]
struct RawFile {
    id: String,
    name: String,
    #[serde(flatten)]
    file_or_folder: FileOrFolder,
}

In this case, unlike the Pagination example, by using serde's rename_all = lowercase, serde will use the variants as the keys to look for in the json data to instantiate FileOrFolder.

#[derive(Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
enum FileOrFolder {
    File {
        #[serde(rename = "mimeType")]
        mime_type: String,
    },
    Folder {
        #[serde(rename = "childCount")]
        child_count: u32,
    },
}

Serde keeps on giving!

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.