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:
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)))