From c25d76e20f5414dd63531f2ac553c9fe6823a2c1 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Mon, 8 Jul 2019 03:29:47 -0700 Subject: [PATCH] Treat deserialization failure as a validation failure. If a ruma-events type fails deserialization, but the input was valid JSON, this should be treated as a validation failure instead of a deserialization failure. In this case, attempt to deserialize the json into a `serde_json::Value`, and only return a deserialization error if that fails. --- src/gen.rs | 30 ++++++++++++++++++++++++++++-- tests/ruma_events_macros.rs | 31 ++++++++++++++++++++++++++----- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/gen.rs b/src/gen.rs index 328eba42..c6b9af1f 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -365,7 +365,20 @@ impl ToTokens for RumaEvent { /// Attempt to create `Self` from parsing a string of JSON data. fn from_str(json: &str) -> Result { - let raw = serde_json::from_str::(json)?; + let raw = match serde_json::from_str::(json) { + Ok(raw) => raw, + Err(error) => match serde_json::from_str::(json) { + Ok(value) => { + return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Validation { + json: value, + message: error.to_string(), + })); + } + Err(error) => { + return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Deserialization { error })); + } + }, + }; Ok(Self { #(#content_field_values)* @@ -400,7 +413,20 @@ impl ToTokens for RumaEvent { /// Attempt to create `Self` from parsing a string of JSON data. fn from_str(json: &str) -> Result { - let raw = serde_json::from_str::(json)?; + let raw = match serde_json::from_str::(json) { + Ok(raw) => raw, + Err(error) => match serde_json::from_str::(json) { + Ok(value) => { + return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Validation { + json: value, + message: error.to_string(), + })); + } + Err(error) => { + return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Deserialization { error })); + } + }, + }; Ok(Self { #(#try_from_field_values)* diff --git a/tests/ruma_events_macros.rs b/tests/ruma_events_macros.rs index 98a5c9ce..21b2b5ce 100644 --- a/tests/ruma_events_macros.rs +++ b/tests/ruma_events_macros.rs @@ -126,13 +126,34 @@ pub trait StateEvent: RoomEvent { fn state_key(&self) -> &str; } +/// An event that is malformed or otherwise invalid. +/// +/// When attempting to create an event from a string of JSON data, an error in the input data may +/// cause deserialization to fail, or the JSON structure may not corresponded to ruma-events's +/// strict definition of the event's schema. If deserialization completely fails, this type will +/// provide a message with details about the deserialization error. If deserialization succeeds but +/// the event is otherwise invalid, a similar message will be provided, as well as a +/// `serde_json::Value` containing the raw JSON data as it was deserialized. #[derive(Debug)] -pub struct InvalidEvent; +pub struct InvalidEvent(InnerInvalidEvent); -impl From for InvalidEvent { - fn from(_: serde_json::Error) -> Self { - Self - } +/// An event that is malformed or otherwise invalid. +#[derive(Debug)] +enum InnerInvalidEvent { + /// An event that failed to deserialize from JSON. + Deserialization { + /// The deserialization error returned by serde. + error: serde_json::Error, + }, + + /// An event that deserialized but failed validation. + Validation { + /// The raw `serde_json::Value` representation of the invalid event. + json: serde_json::Value, + + /// An message describing why the event was invalid. + message: String, + }, } // See note about wrapping macro expansion in a module from `src/lib.rs`