-1

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. 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.

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.

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.

unownone
  • 56
  • 1
  • 6
  • 2
    "sort of works but not really" - is what ways does it accomplish what you want or achieves it sub-optimally? – PitaJ Jan 06 '23 at 22:38
  • 1
    nit: `#[skip_serializing_none]` does nothing here – PitaJ Jan 06 '23 at 22:58
  • @PitaJ updated the question to show examples , and issues. Also kept `#[skip_serializing_none]` because this is my default macro template for the data structures. You are right , so I will be removing it! Thanks! – unownone Jan 06 '23 at 23:11
  • @Stargateur sorry if my question seemed it was seeking for a complete solution! I updated the question to better reflect what I actually require, which is more like a suggestion/ sharing of knowledge if anyone has about this data structure that I have stumbled across . – unownone Jan 06 '23 at 23:12
  • 1
    Do you have power over the JSON data structure or is it fixed? – Finomnis Jan 06 '23 at 23:15
  • 1
    PitaJ's first comment still stands though - please provide the code you tested (including a `main` and `use` statements and everything, including the output/behaviour your code gives, and what bothers you about that output. It's called a [MRE]. Only like that can we guide you towards your goal. – Finomnis Jan 06 '23 at 23:17

1 Answers1

2

Here are my recommendations:

  1. Use just #[serde(tag = "type")] instead of #[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.

    This also has the small benefit of reducing the amount of Boxes involved.

  2. Consider whether all of the different cases in WebflowPropDataType can actually occur everywhere it's used. 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.


Example for #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

PitaJ
  • 12,969
  • 6
  • 36
  • 55