Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Deserialize json into enum

I am trying to deserialize a json but i am unable to get the expected result. Below is my code:

use serde::{Serialize, Deserialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct StudentData{
    stu1: TestResult,
    stu2: TestResult,
    stu3: TestResult,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
enum TestResult{
    #[serde(rename = "fail")]
    Fail,
    #[serde(rename = "absent")]
    Absent,
    Pass(String)
}


fn main() {
    let json_string = "{\"stu1\":\"50\",\"stu2\":\"fail\",\"stu3\":\"absent\"}";
    let s: StudentData = serde_json::from_str(json_string).expect("should provide student data");
    println!("{:#?}", s);
}

The output

StudentData {
    stu1: Pass(
        "50",
    ),
    stu2: Pass(
        "fail",
    ),
    stu3: Pass(
        "absent",
    ),
}

What i am trying to get:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

StudentData {
    stu1: Pass(
        "50",
    ),
    stu2: Fail,
    stu3: Absent,
}

Is this doable?

>Solution :

This behaviour surprised me a bit. Apparently, if you have unit variants in an untagged enum, they get serialized as a null JSON value.

println!("{}", serde_json::to_string(&TestResult::Fail).unwrap());

prints

null

I presume serde expects a null on deserialize likewise. You can get around this by not making the entire enum untagged, but only the Pass variant.

#[derive(Debug, Clone, Serialize, Deserialize)]
enum TestResult {
    #[serde(rename = "fail")]
    Fail,
    #[serde(rename = "absent")]
    Absent,
    #[serde(untagged)]
    Pass(String),
}

(I’m not entirely sure I like your representation, btw. Why is the number of points a string, and not a number? And it should really have its own tag, like "pass": {"score": 50}. (Rounding might be a concern if you have half points. (rel: arbitrary_precision)))

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading