Skip to content

Commit

Permalink
Parse nulls as None on nested serde structs (#473)
Browse files Browse the repository at this point in the history
When parsing a structure nested inside an untagged enum serde treats
keys with a null value as Unit instead of calling visit_none.  This
causes an error of "invalid type: null, expected an
RFC3339-formatted `Option<OffsetDateTime>`".  This change just adds an
implementation for visit_unit so the value will be parsed as None as
expected.
  • Loading branch information
stusmall authored Jun 20, 2022
1 parent e893d31 commit b599d66
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/serde/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,10 @@ macro_rules! well_known {
fn visit_none<E: de::Error>(self) -> Result<Option<OffsetDateTime>, E> {
Ok(None)
}

fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
}
};
}
Expand Down
1 change: 1 addition & 0 deletions tests/integration/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use time::{Date, Duration, Month, OffsetDateTime, PrimitiveDateTime, Time, UtcOf
mod error_conditions;
mod iso8601;
mod macros;
mod rfc2822;
mod rfc3339;
mod timestamps;

Expand Down
55 changes: 55 additions & 0 deletions tests/integration/serde/rfc2822.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use serde::{Deserialize, Serialize};
use serde_test::{assert_tokens, Configure, Token};
use time::serde::rfc2822;
use time::OffsetDateTime;
use time_macros::datetime;

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
struct Test {
#[serde(with = "rfc2822")]
dt: OffsetDateTime,
#[serde(with = "rfc2822::option")]
option_dt: Option<OffsetDateTime>,
}

#[test]
fn serialize_deserialize() {
let value = Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: Some(datetime!(2000-01-01 00:00:00 UTC)),
};
assert_tokens(
&value.compact(),
&[
Token::Struct {
name: "Test",
len: 2,
},
Token::Str("dt"),
Token::BorrowedStr("Sat, 01 Jan 2000 00:00:00 +0000"),
Token::Str("option_dt"),
Token::Some,
Token::BorrowedStr("Sat, 01 Jan 2000 00:00:00 +0000"),
Token::StructEnd,
],
);
}

#[test]
fn parse_json() {
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(untagged)]
enum Wrapper {
A(Test),
}
assert_eq!(
serde_json::from_str::<Wrapper>(
r#"{"dt": "Sat, 01 Jan 2000 00:00:00 +0000", "option_dt": null}"#
)
.unwrap(),
Wrapper::A(Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: None,
})
);
}
19 changes: 18 additions & 1 deletion tests/integration/serde/rfc3339.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct Test {
}

#[test]
fn serialize() {
fn serialize_deserialize() {
let value = Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: Some(datetime!(2000-01-01 00:00:00 UTC)),
Expand Down Expand Up @@ -81,3 +81,20 @@ fn serialize() {
"The offset_second component cannot be formatted into the requested format.",
);
}

#[test]
fn parse_json() {
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(untagged)]
enum Wrapper {
A(Test),
}
assert_eq!(
serde_json::from_str::<Wrapper>("{\"dt\": \"2000-01-01T00:00:00Z\", \"option_dt\": null}")
.unwrap(),
Wrapper::A(Test {
dt: datetime!(2000-01-01 00:00:00 UTC),
option_dt: None,
})
);
}

0 comments on commit b599d66

Please sign in to comment.