//! De-/serialization functions for `Option` objects represented as //! milliseconds since the UNIX epoch. Delegates to `js_int::UInt` to ensure integer size is within //! bounds. use std::time::{Duration, SystemTime, UNIX_EPOCH}; use js_int::UInt; use serde::{ de::{self, Deserialize, Deserializer}, ser::{Serialize, Serializer}, }; /// Serialize an `Option`. /// /// Will fail if integer is greater than the maximum integer that can be unambiguously represented /// by an f64. pub fn serialize(opt_time: &Option, serializer: S) -> Result where S: Serializer, { match opt_time { Some(time) => super::ms_since_unix_epoch::serialize(time, serializer), None => Option::::serialize(&None, serializer), } } /// Deserializes an `Option`. /// /// Will fail if integer is greater than the maximum integer that can be unambiguously represented /// by an f64. pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { Option::::deserialize(deserializer)? .map(|millis| { UNIX_EPOCH .checked_add(Duration::from_millis(millis.into())) .ok_or_else(|| de::Error::custom("input too large for SystemTime")) }) .transpose() } #[cfg(test)] mod tests { use std::time::{Duration, SystemTime, UNIX_EPOCH}; use serde::{Deserialize, Serialize}; use serde_json::json; #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] struct SystemTimeTest { #[serde(with = "super", default, skip_serializing_if = "Option::is_none")] timestamp: Option, } #[test] fn deserialize_some() { let json = json!({ "timestamp": 3000 }); assert_eq!( serde_json::from_value::(json).unwrap(), SystemTimeTest { timestamp: Some(UNIX_EPOCH + Duration::from_millis(3000)) }, ); } #[test] fn deserialize_none_by_absence() { let json = json!({}); assert_eq!( serde_json::from_value::(json).unwrap(), SystemTimeTest { timestamp: None }, ); } #[test] fn deserialize_none_by_null() { let json = json!({ "timestamp": null }); assert_eq!( serde_json::from_value::(json).unwrap(), SystemTimeTest { timestamp: None }, ); } #[test] fn serialize_some() { let request = SystemTimeTest { timestamp: Some(UNIX_EPOCH + Duration::new(2, 0)) }; assert_eq!(serde_json::to_value(&request).unwrap(), json!({ "timestamp": 2000 })); } #[test] fn serialize_none() { let request = SystemTimeTest { timestamp: None }; assert_eq!(serde_json::to_value(&request).unwrap(), json!({})); } }