Serde_json: Complex JSON structure

I’m trying to serialize and deserialize the next JSON structure.

{
    "objects": {
        "type":4,
        "ids":["D1","D2"]
    },
    "data": [
        {
            "stateticks":1798,
            "faultstate":0,
            "state":0
        },
        {
            "stateticks":1798,
            "faultstate":0,
            "state":1
        }
    ],
    "ticks":1808
}

The tricky thing is that the type of the data field is different per
objects.type. I try to solve this by using traits.
See the playgound. All I can't use this method because
But this don't work because i don't know the type of data on beforehand.
An enum would be a good option, but it doesn't work because
the type field is not with the data field.

Someone ideas how I can solve this?

The json structure must remain the same.

current code:

use serde::{Deserialize, Serialize};
// use serde_repr::{Deserialize_repr, Serialize_repr};

pub trait ObjectDataContent {}
pub trait ObjectType {}


// #[derive(Deserialize_repr, Serialize_repr, Debug)]
#[derive(Deserialize, Serialize, Debug)]
#[repr(u32)]
pub enum TLCObjectType {
    Session = 0,
    TLCFacilities = 1,
    Intersection = 2,
    SignalGroup = 3,
    Detector = 4,
    Input = 5,
    Output = 6,
    SpecialVehicleEventGenerator = 7,
    Variable = 8,
}

impl ObjectType for TLCObjectType {}

// Somthing like this?
#[derive(Deserialize, Serialize, Debug)]
#[serde(tag = "t", content = "c")]
enum ObjectDataEnum {
    Detector(Detector),
    Inputs(Inputs),
}

#[derive(Deserialize, Serialize, Debug)]
struct Detector {
    pub stateticks: u32,
    pub state: u32,
    pub faultstate: u32,
}

impl ObjectDataContent for Detector {}

#[derive(Deserialize, Serialize, Debug)]
struct Inputs {
    pub state: u32,
    pub faultstate: u32,
    pub swico: u32,
}

impl ObjectDataContent for Inputs {}

#[derive(Deserialize, Serialize, Debug)]
pub struct ObjectReference<T: ObjectType> {
    pub r#type: T,
    pub ids: Vec<ObjectID>,
}

#[derive(Deserialize, Serialize, Debug)]
pub struct ObjectID(pub String);

#[derive(Deserialize, Serialize, Debug)]
pub struct ObjectData<C: ObjectDataContent, T: ObjectType> {
    pub objects: ObjectReference<T>,
    pub data: Vec<C>,
    pub ticks: u32,
}

fn main() {
    let obj: ObjectData<Detector, TLCObjectType> = ObjectData {
        objects: ObjectReference {
            r#type: TLCObjectType::Detector,
            ids: vec![ObjectID("a".to_string()), ObjectID("b".to_string())],
        },
        data: vec![
            Detector {
                stateticks: 1,
                state: 2,
                faultstate: 3,
            }
        ],
        ticks: 100,
    };
    

    // Convert the Point to a JSON string.
    let serialized = serde_json::to_string_pretty(&obj).unwrap();

    println!("serialized = {}", serialized);

    // Convert the JSON string back to a ObjectData.
    // I need to remove the Detector 
    let deserialized:  ObjectData<Detector, TLCObjectType> = serde_json::from_str(&serialized).unwrap();

    println!("deserialized = {:?}", deserialized);
}

If the objects are different, you can use an untagged repr.

#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum DataVec {
    Detector(Vec<Detector>),
    Inputs(Vec<Inputs>),
}

playground

Thanks didn't think about this option, unfortunately not all objects are different.

How about making an enum with the cases that are different, and then disambiguating based on the integer afterwards?

That is the solution, afterwards i now the type so I can convert it to the right struct.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.