使用 serde 反序列化变量元对象

Deserialize variable meta object with serde

我正在寻找一种优雅的方法来反序列化以下输入:

{
  "products": [

    {
      "id": 1,
      "ptype": "Clothes",
      "description": "some data about clothes",
      "metadata": {
        "colors" : ["blue", "green"],
        "web": false,
        "size": 2
      }
    },
    {
      "id": 4,
      "ptype": "Food",
      "description": "text for foods",
      "metadata": {
        "country": "France",
        "wine": true
      }
    },
    {
      "id": 12,
      "ptype": "EmptyPlaceholder",
      "description": "nothing at all",
      "metadata": {
      }
    }
  ]
}

json 包含一组产品。产品可以由 ptype 字段标识。根据字段的类型,元数据对象不同。例如,如果 ptype 是 Food,那么食物的元数据将是一个字符串(国家)和一个布尔值(酒)。所以产品有一些共同的字段,id、ptype 和 description 以及一些元数据。我想在 Vec<Product>.

中反序列化此 JSON 文件

到目前为止,我使用了以下代码:

use serde::{Deserialize};
use serde_json::Result;

#[derive(Deserialize, Debug)]
struct ClothesData {
    colors : Vec<String>,
    web : bool,
    size: u32,
}

#[derive(Deserialize, Debug)]
struct FoodData {
    country: String,
    wine: bool,
}

#[derive(Deserialize, Debug)]
struct EmptyData {

}

#[derive(Deserialize, Debug)]
enum Metadata {
    ClothesData,
    FoodData,
    EmptyData,
}

#[derive(Deserialize, Debug)]
enum  Ptype {
    Clothes,
    Food,
    EmptyPlaceholder
}

#[derive(Deserialize, Debug)]
struct Product {
    id: u32,
    ptype: Ptype,
    description: Option<String>,
    metadata: Metadata,

}

我不确定如何从这里开始,我想问一下 serde crate 是否可以做到这一点 "automatically"。

这对应于 "adjacently tagged" serde 枚举表示:

use serde::Deserialize;
use serde_json::Result;

#[derive(Deserialize, Debug)]
struct Clothes {
    colors: Vec<String>,
    web: bool,
    size: u32,
}

#[derive(Deserialize, Debug)]
struct Food {
    country: String,
    wine: bool,
}

#[derive(Deserialize, Debug)]
struct Empty {}

#[derive(Deserialize, Debug)]
#[serde(tag = "ptype", content = "metadata")]
enum Kind {
    Clothes(Clothes),
    Food(Food),
    EmptyPlaceholder(Empty),
}

#[derive(Deserialize, Debug)]
struct Product {
    id: u32,
    description: Option<String>,
    #[serde(flatten)]
    kind: Kind,
}

#[derive(Deserialize, Debug)]
struct Root {
    products: Vec<Product>,
}

fn main() -> Result<()> {
    let data = r#"
    {
        "products": [

            {
              "id": 1,
              "ptype": "Clothes",
              "description": "some data about clothes",
              "metadata": {
                "colors" : ["blue", "green"],
                "web": false,
                "size": 2
              }
            },
            {
              "id": 4,
              "ptype": "Food",
              "description": "text for foods",
              "metadata": {
                "country": "France",
                "wine": true
              }
            },
            {
              "id": 12,
              "ptype": "EmptyPlaceholder",
              "description": "nothing at all",
              "metadata": {
              }
            }
        ]
    }"#;

    let root: Root = serde_json::from_str(data)?;
    println!("{:#?}", root);

    Ok(())
}