How can I deserialize an optional field with custom functions using Serde?

I want to serialize and deserialize chrono::NaiveDate using custom functions, but the Serde book does not cover this functionality, and the code docs don't help either.

 #[macro_use] extern crate serde_derive; extern crate serde; extern crate serde_json; extern crate chrono; use chrono::NaiveDate; mod date_serde { use chrono::NaiveDate; use serde::{self, Deserialize, Serializer, Deserializer}; pub fn serialize<S>(date: &Option<NaiveDate>, s: S) -> Result<S::Ok, S::Error> where S: Serializer { if let Some(ref d) = *date { return s.serialize_str(&d.format("%Y-%m-%d").to_string()) } s.serialize_none() } pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<NaiveDate>, D::Error> where D: Deserializer<'de> { let s: Option<String> = Option::deserialize(deserializer)?; if let Some(s) = s { return Ok(Some(NaiveDate::parse_from_str(&s, "%Y-%m-%d").map_err(serde::de::Error::custom)?)) } Ok(None) } } #[derive(Debug, Serialize, Deserialize)] struct Test { pub i: u64, #[serde(with = "date_serde")] pub date: Option<NaiveDate>, } fn main() { let mut test: Test = serde_json::from_str(r#"{"i": 3, "date": "2015-02-03"}"#).unwrap(); assert_eq!(test.i, 3); assert_eq!(test.date, Some(NaiveDate::from_ymd(2015, 02, 03))); test = serde_json::from_str(r#"{"i": 5}"#).unwrap(); assert_eq!(test.i, 5); assert_eq!(test.date, None); } 

I know that Option<chrono::NaiveDate> can be easily deserialized to Serde, because Chrono has support for Serde , but . I am trying to learn Serde, so I want to implement it myself. When I run this code, I have an error:

 thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ErrorImpl { code: Message("missing field `date`"), line: 1, column: 8 }', /checkout/src/libcore/result.rs:859 note: Run with `RUST_BACKTRACE=1` for a backtrace. 
+5
source share
1 answer

An Option field here does not tell the deserializer that the field may not exist. Rather, it assumes that it contains a field with empty or null content ( none in terms of Cerde). In serde_json , for example, Option<String> is the JavaScript equivalent for "either null or string " ( null | string in TypeScript / stream notation). This code below works fine:

 let test: Test = serde_json::from_str(r#"{"i": 5, "date": null}"#).unwrap(); assert_eq!(test.i, 5); assert_eq!(test.date, None); 

Fortunately, the deserialization process can become more permissive by simply adding the serde(default) attribute ( Option::default yields none ):

 #[derive(Debug, Serialize, Deserialize)] struct Test { pub i: u64, #[serde(default)] #[serde(with = "date_serde")] pub date: Option<NaiveDate>, } 

Playground

See also How to deserialize a JSON file that contains NULL values ​​with Serde? (not a duplicate, but contains a similar and suitable use case)

+2
source

Source: https://habr.com/ru/post/1268427/


All Articles