Skip to content

Commit

Permalink
Add special handling for dates behind feature flag
Browse files Browse the repository at this point in the history
  • Loading branch information
ranile committed Aug 31, 2023
1 parent 620cb3d commit 0586dcc
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 4 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,6 @@ debug = true

[patch.crates-io]
proptest = { git = "https://github.com/RReverser/proptest", branch = "fix-wasm" }

[features]
special-dates = []
17 changes: 15 additions & 2 deletions src/de.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use js_sys::{Array, ArrayBuffer, JsString, Number, Object, Symbol, Uint8Array};
use js_sys::{Array, ArrayBuffer, Date, JsString, Number, Object, Symbol, Uint8Array};
use serde::de::value::{MapDeserializer, SeqDeserializer};
use serde::de::{self, IntoDeserializer};
use std::convert::TryFrom;
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt};
use crate::SPECIAL_DATE_PREFIX;

use super::{static_str_to_js, Error, ObjectExt, Result};

Expand Down Expand Up @@ -291,7 +292,19 @@ impl<'de> de::Deserializer<'de> for Deserializer {
// https://github.com/serde-rs/serde/issues/1183 is implemented / fixed on serde side.
!Symbol::iterator().js_in(&self.value)
{
self.deserialize_map(visitor)
// `Date` gets deserialized to an empty object, which is pretty useless.
// special case to be an ISO string
if cfg!(feature = "special-dates") {
match self.value.dyn_ref::<Date>() {
Some(date) => {
let iso_string = date.to_iso_string().as_string().expect_throw("to_iso_string returns a valid string");
visitor.visit_string(format!("{}{}", SPECIAL_DATE_PREFIX, iso_string))
}
None => self.deserialize_map(visitor)
}
} else {
self.deserialize_map(visitor)
}
} else {
self.invalid_type(visitor)
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ pub use de::Deserializer;
pub use error::Error;
pub use ser::Serializer;

pub(crate) const SPECIAL_DATE_PREFIX: &'static str = "$::date:";

type Result<T> = std::result::Result<T, Error>;

fn static_str_to_js(s: &'static str) -> JsString {
Expand Down
19 changes: 17 additions & 2 deletions src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use js_sys::{Array, JsString, Map, Number, Object, Uint8Array};
use serde::ser::{self, Error as _, Serialize};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use crate::SPECIAL_DATE_PREFIX;

use super::{static_str_to_js, Error, ObjectExt};

Expand Down Expand Up @@ -308,10 +309,10 @@ impl<'s> ser::Serializer for &'s Serializer {

serialize_f32(f32);
serialize_f64(f64);

serialize_str(&str);
}



fn serialize_i64(self, v: i64) -> Result {
if self.serialize_large_number_types_as_bigints {
return Ok(v.into());
Expand Down Expand Up @@ -473,4 +474,18 @@ impl<'s> ser::Serializer for &'s Serializer {
self.serialize_struct(variant, len)?,
))
}

fn serialize_str(self, v: &str) -> Result {
if cfg!(feature = "special-dates") {
match v.strip_prefix(SPECIAL_DATE_PREFIX) {
Some(v) => {
let date = js_sys::Date::new(&v.into());
Ok(date.into())
}
None => Ok(v.into())
}
} else {
Ok(v.into())
}
}
}
19 changes: 19 additions & 0 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -819,3 +819,22 @@ fn serde_default_fields() {
// Check that it parses successfully despite the missing field.
let _struct: Struct = from_value(obj).unwrap();
}

#[test]
#[cfg(feature = "special-dates")]
fn dates_are_serialized_as_strings() {
let date = js_sys::Date::new_0();
let object = Object::new();
js_sys::Reflect::set(&object, &"date".into(), &date).unwrap();
let value = object.into();
let mut value: serde_json::Value = from_value(value).unwrap();

let obj = value.as_object_mut().unwrap();
obj.insert("anotherValue".to_string(), serde_json::Value::String("something".to_string()));
assert!(obj.get("date").unwrap().as_str().unwrap().starts_with("$::date:"));

let to_value = value.serialize(&Serializer::json_compatible()).unwrap();
let date = js_sys::Reflect::get(&to_value, &"date".into()).unwrap();
assert!(date.dyn_into::<js_sys::Date>().is_ok())

}

0 comments on commit 0586dcc

Please sign in to comment.