diff --git a/src/gen.rs b/src/gen.rs index c6b9af1f..96529e43 100644 --- a/src/gen.rs +++ b/src/gen.rs @@ -360,40 +360,31 @@ impl ToTokens for RumaEvent { } quote! { - impl std::str::FromStr for #content_name { - type Err = crate::InvalidEvent; + impl<'de> serde::Deserialize<'de> for crate::EventResult<#content_name> { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let json = serde_json::Value::deserialize(deserializer)?; - /// Attempt to create `Self` from parsing a string of JSON data. - fn from_str(json: &str) -> Result { - let raw = match serde_json::from_str::(json) { + let raw: raw::#content_name = match serde_json::from_value(json.clone()) { Ok(raw) => raw, - Err(error) => match serde_json::from_str::(json) { - Ok(value) => { - return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Validation { - json: value, + Err(error) => { + return Ok(crate::EventResult::Err(crate::InvalidEvent( + crate::InnerInvalidEvent::Validation { + json, message: error.to_string(), - })); - } - Err(error) => { - return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Deserialization { error })); - } - }, + }, + ))); + } }; - Ok(Self { + Ok(crate::EventResult::Ok(#content_name { #(#content_field_values)* - }) + })) } } - impl<'a> std::convert::TryFrom<&'a str> for #content_name { - type Error = crate::InvalidEvent; - - /// Attempt to create `Self` from parsing a string of JSON data. - fn try_from(json: &'a str) -> Result { - std::str::FromStr::from_str(json) - } - } } } else { TokenStream::new() @@ -408,38 +399,28 @@ impl ToTokens for RumaEvent { #content - impl std::str::FromStr for #name { - type Err = crate::InvalidEvent; + impl<'de> serde::Deserialize<'de> for crate::EventResult<#name> { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let json = serde_json::Value::deserialize(deserializer)?; - /// Attempt to create `Self` from parsing a string of JSON data. - fn from_str(json: &str) -> Result { - let raw = match serde_json::from_str::(json) { + let raw: raw::#name = match serde_json::from_value(json.clone()) { Ok(raw) => raw, - Err(error) => match serde_json::from_str::(json) { - Ok(value) => { - return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Validation { - json: value, + Err(error) => { + return Ok(crate::EventResult::Err(crate::InvalidEvent( + crate::InnerInvalidEvent::Validation { + json, message: error.to_string(), - })); - } - Err(error) => { - return Err(crate::InvalidEvent(crate::InnerInvalidEvent::Deserialization { error })); - } - }, + }, + ))); + } }; - Ok(Self { + Ok(crate::EventResult::Ok(#name { #(#try_from_field_values)* - }) - } - } - - impl<'a> std::convert::TryFrom<&'a str> for #name { - type Error = crate::InvalidEvent; - - /// Attempt to create `Self` from parsing a string of JSON data. - fn try_from(json: &'a str) -> Result { - std::str::FromStr::from_str(json) + })) } } diff --git a/tests/ruma_events_macros.rs b/tests/ruma_events_macros.rs index 21b2b5ce..dd47dc7b 100644 --- a/tests/ruma_events_macros.rs +++ b/tests/ruma_events_macros.rs @@ -80,6 +80,28 @@ impl<'de> Deserialize<'de> for EventType { } } +/// The result of deserializing an event, which may or may not be valid. +#[derive(Debug)] +pub enum EventResult { + /// `T` deserialized and validated successfully. + Ok(T), + + /// `T` deserialized but was invalid. + /// + /// `InvalidEvent` contains the original input. + Err(InvalidEvent), +} + +impl EventResult { + /// Convert `EventResult` into the equivalent `std::result::Result`. + pub fn into_result(self) -> Result { + match self { + EventResult::Ok(t) => Ok(t), + EventResult::Err(invalid_event) => Err(invalid_event), + } + } +} + /// A basic event. pub trait Event where @@ -140,12 +162,6 @@ pub struct InvalidEvent(InnerInvalidEvent); /// 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. @@ -165,6 +181,8 @@ pub mod common_case { use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId}; use serde_json::Value; + use super::EventResult; + ruma_event! { /// Informs the room about what room aliases it has been given. AliasesEvent { @@ -248,7 +266,8 @@ pub mod common_case { fn deserialization() { let json = r##"{"content":{"aliases":["#room:example.org"]},"event_id":"$h29iv0s8:example.com","origin_server_ts":1,"prev_content":{"aliases":[]},"room_id":"!n8f893n9:example.com","sender":"@carl:example.com","state_key":"example.com","unsigned":{"foo":"bar"},"type":"m.room.aliases"}"##; - let actual: AliasesEvent = json.parse().unwrap(); + let event_result: EventResult = serde_json::from_str(json).unwrap(); + let actual: AliasesEvent = event_result.into_result().unwrap(); let expected = AliasesEvent { content: AliasesEventContent {