简体   繁体   English

如何使用枚举将 json object 反序列化为 rust 可理解的代码?

[英]How to deserialize a json object into rust understandable code using enums?

I need to deserialize ( and later on serialize ) a piece of data that has this type of a structure:我需要反序列化(以及稍后序列化)一段具有这种结构的数据:

{
  "type": "TypeApplication",
  "val": {
    "con": {
      "type": "TypeConstructor",
      "val": [
        "Builtin",
        "Record"
      ]
    },
    "arg": {
      "type": "RowCons",
      "val": {
        "label": "953e3dd6-826e-1985-cb99-fd4ed4da754e",
        "type": {
          "type": "TypeApplication",
          "val": {
            "con": {
              "type": "TypeConstructor",
              "val": [
                "Builtin",
                "List"
              ]
            },
            "arg": {
              "type": "Element",
              "meta": {
                "multiLine": true
              }
            }
          },
          "system": {
            "label": "nullam-senectus-port - Text",
            "isBindable": true,
            "defaultValue": [
              {
                "id": "4a05486f-f24d-45f8-ae13-ab05f824d74d",
                "type": "String",
                "pluginType": "Basic",
                "data": {
                  "value": "Nullam senectus porttitor in eget. Eget rutrum leo interdum."
                },
                "children": [],
                "text": true
              }
            ],
            "isUnlinked": false,
            "isDefault": false
          }
        },
        "tail": {
          "type": "RowCons",
          "val": {
            "label": "94f603df-d585-b45a-4252-9ec77cf5b13c",
            "type": {
              "type": "TypeApplication",
              "val": {
                "con": {
                  "type": "TypeConstructor",
                  "val": [
                    "Builtin",
                    "List"
                  ]
                },
                "arg": {
                  "type": "Element",
                  "meta": {
                    "multiLine": true
                  }
                }
              },
              "system": {
                "label": "best-services - Text",
                "isBindable": true,
                "defaultValue": [
                  {
                    "id": "6265ca45-3f69-4844-97e2-c05bbfb9fee5",
                    "type": "String",
                    "pluginType": "Basic",
                    "data": {
                      "value": "Best Services"
                    },
                    "children": [],
                    "text": true
                  }
                ]
              }
            },
            "tail": {
              "type": "RowEmpty"
            }
          }
        }
      }
    }
  }
}

I do not know what this data exactly is, but I know this is trying to represent a function/element that takes in values and defaults for those values as parameters/properties.我不知道这个数据到底是什么,但我知道这是试图表示一个函数/元素,它接受值和这些值的默认值作为参数/属性。

I want to deserialize it using serde and consequently serialize it too.我想使用serde反序列化它,然后也序列化它。 I have so far been able to write something that sort of works but not really:到目前为止,我已经能够写出一些类似的作品,但不是真的:

#[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(tag = "type", content = "val")]
pub enum WebflowPropDataType {
    TypeApplication {
        con: Box<WebflowPropDataType>, // Normally Passes the Type Constructor
        arg: Box<WebflowPropDataType>, // Normally Passes the Row Constructor
    },
    TypeConstructor(Vec<String>), // Stores Value of TypeConstructor
    RowCons {
        label: String, // Stores the label of the Row
        #[serde(rename = "type")]
        row_con_type: Box<WebflowPropDataType>, // Stores the type of the Row
        tail: Box<WebflowPropDataType>,
    },
    RowEmpty, // For Ending the recursive usage of rowConstructor
}

#[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct WebflowRowConDataType {
    #[serde(rename = "type")]
    val_type: String, // TypeApplication
    val: Box<WebflowPropDataType>,
} 

This works for a structure like this:这适用于这样的结构:

{
    "type": "TypeApplication",
    "val":{
        "con": {
            "type": "TypeConstructor",
            "val": []
          },       
        "arg": {
            "type": "RowEmpty"
        }
    }
}

but would fail if I try to work with initial example.但如果我尝试使用初始示例,将会失败。 I know this may be due to the lack of a proper arg type or maybe even the TypeApplication Enum hand is malformed.我知道这可能是由于缺少适当的arg类型,或者甚至TypeApplication Enum hand 格式不正确。

I do see that a adjancent typing solution would be enough for most of the times but there are cases as seen in the example structure that there is a third value called system and I am unable to determine what type of approach would help me achieve this type of outcome.我确实看到一个相邻的类型解决方案在大多数情况下就足够了,但是在示例结构中看到的情况是存在第三个值称为system ,我无法确定哪种类型的方法可以帮助我实现这种类型结果。

How should I approach this problem in order to generate this type of code.我应该如何处理这个问题才能生成这种类型的代码。

I am not asking anyone to write me a solution but to give me suggestion as to what my approach should be?我不是要任何人给我写一个解决方案,而是要给我建议我的方法应该是什么? Whether you'd know what type of data this is/how to generated this, or even if there are some other library I should look into to manipulate this type of data or maybe look at other approaches.无论您是否知道这是什么类型的数据/如何生成它,或者即使有一些其他的库我也应该研究一下来操作这种类型的数据或者看看其他的方法。

PS : - My end goal is to be able to generate / serialize this type of JSON code from already contained knowledge of properties and default values of a function/object. PS : - 我的最终目标是能够从已经包含的函数/对象的属性和默认值知识中生成/序列化这种类型的 JSON 代码。

Here are my recommendations:以下是我的建议:

  1. Use just #[serde(tag = "type")] instead of #[serde(tag = "type", content = "val")] .只使用#[serde(tag = "type")]而不是#[serde(tag = "type", content = "val")] You will have to handle val manually (extracting the current enum members into separate structs), but this allows you to also handle TypeApplication.system and Element.meta .您将不得不手动处理val (将当前枚举成员提取到单独的结构中),但这也允许您处理TypeApplication.systemElement.meta

    This also has the small benefit of reducing the amount of Box es involved.这也有减少所涉及的Box数量的小好处。

  2. Consider whether all of the different cases in WebflowPropDataType can actually occur everywhere it's used.考虑WebflowPropDataType中的所有不同情况是否实际上可以在使用它的任何地方发生。 If not (maybe Element can only happen under TypeApplication.val.arg ), then you may want to split the enum into multiple so that this is reflected in the type system.如果不是(也许Element只能在TypeApplication.val.arg下发生),那么您可能希望将枚举拆分为多个,以便在类型系统中反映出来。


Example for #1: #1 的示例:

use serde::{Serialize, Deserialize};

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TypeApplicationVal {
    con: WebflowPropDataType, // Normally Passes the Type Constructor
    arg: WebflowPropDataType, // Normally Passes the Row Constructor
}

// #[skip_serializing_none]
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct TypeApplicationSystem {
    label: String,
    #[serde(rename = "isBindable")]
    is_bindable: bool,

    // TODO: defaultValue

    #[serde(rename = "isUnlinked")]
    #[serde(skip_serializing_if = "Option::is_none")]
    is_unlinked: Option<bool>,
    #[serde(rename = "isDefault")]
    #[serde(skip_serializing_if = "Option::is_none")]
    is_default: Option<bool>,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct RowConsVal {
    label: String, // Stores the label of the Row
    #[serde(rename = "type")]
    typ: WebflowPropDataType, // Stores the type of the Row
    tail: WebflowPropDataType,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct ElementMeta {
    #[serde(rename = "multiLine")]
    multi_line: bool,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(tag = "type")]
pub enum WebflowPropDataType {
    TypeApplication {
        val: Box<TypeApplicationVal>,
        #[serde(skip_serializing_if = "Option::is_none")]
        system: Option<TypeApplicationSystem>,
    },
    TypeConstructor {
        val: Vec<String> // Stores Value of TypeConstructor
    },
    RowCons {
        val: Box<RowConsVal>,
    },
    Element {
        meta: ElementMeta,
    },
    RowEmpty, // For Ending the recursive usage of rowConstructor
}

playground 操场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM