From 91d564dcf812196f7497fe93ea5591eab8d83d1d Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Tue, 3 Sep 2019 12:01:29 -0700 Subject: [PATCH] WIP --- Cargo.toml | 2 +- src/lib.rs | 185 ++++++++---- src/stripped.rs | 755 +++++++++++++++++++++++++++++++----------------- 3 files changed, 618 insertions(+), 324 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5ffd3196..052212f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ edition = "2018" [dependencies] ruma-identifiers = "0.14.0" -ruma-events-macros = "0.1.0" +ruma-events-macros = { version = "0.1.0", path = "../ruma-events-macros" } serde_json = "1.0.40" [dependencies.js_int] diff --git a/src/lib.rs b/src/lib.rs index c9539ae4..230ba1cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,9 +115,10 @@ #![deny(warnings)] use std::{ + collections::HashMap, error::Error, fmt::{Debug, Display, Error as FmtError, Formatter, Result as FmtResult}, - str::FromStr, + hash::Hash, }; use js_int::UInt; @@ -129,19 +130,19 @@ use serde::{ }; use serde_json::Value; -pub use custom::CustomEvent; -pub use custom_room::CustomRoomEvent; -pub use custom_state::CustomStateEvent; +// pub use custom::CustomEvent; +// pub use custom_room::CustomRoomEvent; +// pub use custom_state::CustomStateEvent; #[macro_use] mod macros; pub mod call; -/// Enums for heterogeneous collections of events. -pub mod collections { - pub mod all; - pub mod only; -} +// /// Enums for heterogeneous collections of events. +// pub mod collections { +// pub mod all; +// pub mod only; +// } pub mod direct; pub mod dummy; pub mod forwarded_room_key; @@ -261,6 +262,43 @@ impl EventResult { EventResult::Err(invalid_event) => Err(invalid_event), } } + + /// Helper for creating a validation error with an error message and the JSON that failed + /// validation. + #[inline] + pub(crate) fn validation_error(message: String, json: serde_json::Value) -> Self { + EventResult::Err(InvalidEvent(InnerInvalidEvent::Validation { + json, + message, + })) + } +} + +impl<'de, K, V> Deserialize<'de> for EventResult> +where + K: for<'inner> Deserialize<'inner> + Eq + Hash, + V: for<'inner> Deserialize<'inner>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let json = serde_json::Value::deserialize(deserializer)?; + + let hash_map: HashMap = match serde_json::from_value(json.clone()) { + Ok(hash_map) => hash_map, + Err(error) => { + return Ok(EventResult::Err(InvalidEvent( + InnerInvalidEvent::Validation { + json, + message: error.to_string(), + }, + ))); + } + }; + + Ok(EventResult::Ok(hash_map)) + } } /// An error when attempting to create a value from a string via the `FromStr` trait. @@ -320,6 +358,29 @@ impl<'de> Deserialize<'de> for Empty { } } +impl<'de> Deserialize<'de> for EventResult { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let json = serde_json::Value::deserialize(deserializer)?; + + let empty: Empty = match serde_json::from_value(json.clone()) { + Ok(empty) => empty, + Err(error) => { + return Ok(EventResult::Err(InvalidEvent( + InnerInvalidEvent::Validation { + json, + message: error.to_string(), + }, + ))); + } + }; + + Ok(EventResult::Ok(empty)) + } +} + /// The type of an event. #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum EventType { @@ -464,7 +525,9 @@ pub enum EventType { /// A basic event. pub trait Event where - Self: Debug + FromStr + Serialize, + Self: Debug + Serialize + Sized, + for<'de> EventResult: Deserialize<'de>, + for<'de> EventResult: Deserialize<'de>, { /// The type of this event's `content` field. type Content: Debug + Serialize; @@ -477,7 +540,11 @@ where } /// An event within the context of a room. -pub trait RoomEvent: Event { +pub trait RoomEvent: Event +where + for<'de> EventResult: Deserialize<'de>, + for<'de> EventResult<::Content>: Deserialize<'de>, +{ /// The unique identifier for the event. fn event_id(&self) -> &EventId; @@ -499,7 +566,11 @@ pub trait RoomEvent: Event { } /// An event that describes persistent state about a room. -pub trait StateEvent: RoomEvent { +pub trait StateEvent: RoomEvent +where + for<'de> EventResult: Deserialize<'de>, + for<'de> EventResult<::Content>: Deserialize<'de>, +{ /// The previous content for this state key, if any. fn prev_content(&self) -> Option<&Self::Content>; @@ -507,56 +578,56 @@ pub trait StateEvent: RoomEvent { fn state_key(&self) -> &str; } -mod custom { - use ruma_events_macros::ruma_event; - use serde_json::Value; +// mod custom { +// use ruma_events_macros::ruma_event; +// use serde_json::Value; - ruma_event! { - /// A custom basic event not covered by the Matrix specification. - CustomEvent { - kind: Event, - event_type: Custom, - content_type_alias: { - /// The payload for `CustomEvent`. - Value - }, - } - } -} +// ruma_event! { +// /// A custom basic event not covered by the Matrix specification. +// CustomEvent { +// kind: Event, +// event_type: Custom, +// content_type_alias: { +// /// The payload for `CustomEvent`. +// Value +// }, +// } +// } +// } -mod custom_room { - use ruma_events_macros::ruma_event; - use serde_json::Value; +// mod custom_room { +// use ruma_events_macros::ruma_event; +// use serde_json::Value; - ruma_event! { - /// A custom room event not covered by the Matrix specification. - CustomRoomEvent { - kind: RoomEvent, - event_type: Custom, - content_type_alias: { - /// The payload for `CustomRoomEvent`. - Value - }, - } - } -} +// ruma_event! { +// /// A custom room event not covered by the Matrix specification. +// CustomRoomEvent { +// kind: RoomEvent, +// event_type: Custom, +// content_type_alias: { +// /// The payload for `CustomRoomEvent`. +// Value +// }, +// } +// } +// } -mod custom_state { - use ruma_events_macros::ruma_event; - use serde_json::Value; +// mod custom_state { +// use ruma_events_macros::ruma_event; +// use serde_json::Value; - ruma_event! { - /// A custom state event not covered by the Matrix specification. - CustomStateEvent { - kind: StateEvent, - event_type: Custom, - content_type_alias: { - /// The payload for `CustomStateEvent`. - Value - }, - } - } -} +// ruma_event! { +// /// A custom state event not covered by the Matrix specification. +// CustomStateEvent { +// kind: StateEvent, +// event_type: Custom, +// content_type_alias: { +// /// The payload for `CustomStateEvent`. +// Value +// }, +// } +// } +// } impl Display for EventType { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { diff --git a/src/stripped.rs b/src/stripped.rs index ba9d6117..5e9851c2 100644 --- a/src/stripped.rs +++ b/src/stripped.rs @@ -5,11 +5,11 @@ //! state event to be created, when the other fields can be inferred from a larger context, or where //! the other fields are otherwise inapplicable. -use std::{convert::TryFrom, str::FromStr}; +use std::convert::TryFrom; use ruma_identifiers::UserId; -use serde::{Serialize, Serializer}; -use serde_json::{from_value, to_string, Value}; +use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; +use serde_json::from_value; use crate::{ room::{ @@ -20,7 +20,7 @@ use crate::{ power_levels::PowerLevelsEventContent, third_party_invite::ThirdPartyInviteEventContent, topic::TopicEventContent, }, - EventType, InnerInvalidEvent, InvalidEvent, + EventResult, EventType, InnerInvalidEvent, InvalidEvent, }; /// A stripped-down version of a state event that is included along with some other events. @@ -81,207 +81,6 @@ pub struct StrippedStateContent { pub sender: UserId, } -impl FromStr for StrippedState { - type Err = InvalidEvent; - - /// Attempt to create `Self` from parsing a string of JSON data. - fn from_str(json: &str) -> Result { - let value = match serde_json::from_str::(json) { - Ok(value) => value, - Err(error) => match serde_json::from_str::(json) { - Ok(value) => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: error.to_string(), - })); - } - Err(error) => { - return Err(InvalidEvent(InnerInvalidEvent::Deserialization { error })); - } - }, - }; - - let event_type_value = match value.get("type") { - Some(value) => value.clone(), - None => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: "missing field `type`".to_string(), - })) - } - }; - - let event_type = match from_value::(event_type_value.clone()) { - Ok(event_type) => event_type, - Err(error) => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: error.to_string(), - })) - } - }; - - match event_type { - EventType::RoomAliases => Ok(StrippedState::RoomAliases(json.parse()?)), - EventType::RoomAvatar => Ok(StrippedState::RoomAvatar(json.parse()?)), - EventType::RoomCanonicalAlias => Ok(StrippedState::RoomCanonicalAlias(json.parse()?)), - EventType::RoomCreate => Ok(StrippedState::RoomCreate(json.parse()?)), - EventType::RoomGuestAccess => Ok(StrippedState::RoomGuestAccess(json.parse()?)), - EventType::RoomHistoryVisibility => { - Ok(StrippedState::RoomHistoryVisibility(json.parse()?)) - } - EventType::RoomJoinRules => Ok(StrippedState::RoomJoinRules(json.parse()?)), - EventType::RoomMember => Ok(StrippedState::RoomMember(json.parse()?)), - EventType::RoomName => Ok(StrippedState::RoomName(json.parse()?)), - EventType::RoomPowerLevels => Ok(StrippedState::RoomPowerLevels(json.parse()?)), - EventType::RoomThirdPartyInvite => { - Ok(StrippedState::RoomThirdPartyInvite(json.parse()?)) - } - EventType::RoomTopic => Ok(StrippedState::RoomTopic(json.parse()?)), - _ => Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: "not a state event".to_string(), - })), - } - } -} - -impl<'a> TryFrom<&'a str> for StrippedState { - type Error = InvalidEvent; - - /// Attempt to create `Self` from parsing a string of JSON data. - fn try_from(json: &'a str) -> Result { - FromStr::from_str(json) - } -} - -impl Serialize for StrippedState { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match *self { - StrippedState::RoomAliases(ref event) => event.serialize(serializer), - StrippedState::RoomAvatar(ref event) => event.serialize(serializer), - StrippedState::RoomCanonicalAlias(ref event) => event.serialize(serializer), - StrippedState::RoomCreate(ref event) => event.serialize(serializer), - StrippedState::RoomGuestAccess(ref event) => event.serialize(serializer), - StrippedState::RoomHistoryVisibility(ref event) => event.serialize(serializer), - StrippedState::RoomJoinRules(ref event) => event.serialize(serializer), - StrippedState::RoomMember(ref event) => event.serialize(serializer), - StrippedState::RoomName(ref event) => event.serialize(serializer), - StrippedState::RoomPowerLevels(ref event) => event.serialize(serializer), - StrippedState::RoomThirdPartyInvite(ref event) => event.serialize(serializer), - StrippedState::RoomTopic(ref event) => event.serialize(serializer), - } - } -} - -impl FromStr for StrippedStateContent -where - C: FromStr, - ::Err: ToString, -{ - type Err = InvalidEvent; - - /// Attempt to create `Self` from parsing a string of JSON data. - fn from_str(json: &str) -> Result { - let value = match serde_json::from_str::(json) { - Ok(value) => value, - Err(error) => match serde_json::from_str::(json) { - Ok(value) => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: error.to_string(), - })); - } - Err(error) => { - return Err(InvalidEvent(InnerInvalidEvent::Deserialization { error })); - } - }, - }; - - let event_type_value = match value.get("type") { - Some(value) => value.clone(), - None => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: "missing field `type`".to_string(), - })) - } - }; - - let event_type = match from_value::(event_type_value.clone()) { - Ok(event_type) => event_type, - Err(error) => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: error.to_string(), - })) - } - }; - - let content = match value.get("content") { - Some(content_value) => match content_value.as_object() { - Some(content) => content, - None => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: "field `content` must be an object".to_string(), - })) - } - }, - None => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: "missing field `content`".to_string(), - })) - } - }; - - // Unwrap is safe because we already know this can deserialize to a `Value`. - let json_string = to_string(content).unwrap(); - - match event_type { - EventType::RoomAliases => stripped_state_content(&json_string, event_type, value), - EventType::RoomAvatar => stripped_state_content(&json_string, event_type, value), - EventType::RoomCanonicalAlias => { - stripped_state_content(&json_string, event_type, value) - } - EventType::RoomCreate => stripped_state_content(&json_string, event_type, value), - EventType::RoomGuestAccess => stripped_state_content(&json_string, event_type, value), - EventType::RoomHistoryVisibility => { - stripped_state_content(&json_string, event_type, value) - } - EventType::RoomJoinRules => stripped_state_content(&json_string, event_type, value), - EventType::RoomMember => stripped_state_content(&json_string, event_type, value), - EventType::RoomName => stripped_state_content(&json_string, event_type, value), - EventType::RoomPowerLevels => stripped_state_content(&json_string, event_type, value), - EventType::RoomThirdPartyInvite => { - stripped_state_content(&json_string, event_type, value) - } - EventType::RoomTopic => stripped_state_content(&json_string, event_type, value), - _ => Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: "not a state event".to_string(), - })), - } - } -} - -impl<'a, C> TryFrom<&'a str> for StrippedStateContent -where - C: FromStr, - ::Err: ToString, -{ - type Error = InvalidEvent; - - /// Attempt to create `Self` from parsing a string of JSON data. - fn try_from(json: &'a str) -> Result { - FromStr::from_str(json) - } -} - /// A stripped-down version of the *m.room.aliases* event. pub type StrippedRoomAliases = StrippedStateContent; @@ -318,75 +117,499 @@ pub type StrippedRoomThirdPartyInvite = StrippedStateContent; -/// Reduces the boilerplate in the match arms of `impl FromStr for StrippedState`. -#[inline] -fn stripped_state_content( - json: &str, - event_type: EventType, - value: Value, -) -> Result, InvalidEvent> -where - C: FromStr, - ::Err: ToString, -{ - let content = match json.parse::() { - Ok(content) => content, - Err(error) => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: error.to_string(), - })) - } - }; +impl<'de> Deserialize<'de> for EventResult { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let value = serde_json::Value::deserialize(deserializer)?; - Ok(StrippedStateContent { - content, - event_type, - state_key: match value.get("state_key") { - Some(state_key_value) => match state_key_value.as_str() { - Some(state_key) => state_key.to_string(), - None => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: "field `state_key` must be a string".to_string(), - })) - } - }, + let event_type_value = match value.get("type") { + Some(value) => value.clone(), None => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { + return Ok(EventResult::Err(InvalidEvent(InnerInvalidEvent::Validation { json: value, - message: "missing field `state_key`".to_string(), - })) + message: "missing field `type`".to_string(), + }))) } - }, - sender: match value.get("sender") { - Some(sender_value) => match sender_value.as_str() { - Some(sender_str) => match UserId::try_from(sender_str) { - Ok(sender) => sender, - Err(error) => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: error.to_string(), - })) - } - }, - None => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: "field `sender` must be a string".to_string(), - })) - } - }, + }; + + let event_type = match from_value::(event_type_value.clone()) { + Ok(event_type) => event_type, + Err(error) => { + return Ok(EventResult::Err(InvalidEvent(InnerInvalidEvent::Validation { + json: value, + message: error.to_string(), + }))) + } + }; + + let content = match value.get("content") { + Some(content_value) => content_value, None => { - return Err(InvalidEvent(InnerInvalidEvent::Validation { - json: value, - message: "missing field `sender`".to_string(), - })) + return Ok(EventResult::validation_error("missing field `content`".to_string(), value)) } - }, - }) + }; + + let stripped_state = match event_type { + // TODO: On the next stream, start with doing the other variants in this match. + EventType::RoomAliases => { + let content_result = match from_value::>(content.clone()) { + Ok(content_result) => content_result, + Err(error) => return Err(D::Error::custom(error)), + }; + + let content = match content_result { + EventResult::Ok(content) => content, + EventResult::Err(error) => return Ok(EventResult::Err(error)), + }; + + StrippedState::RoomAliases(StrippedStateContent { + content, + event_type, + state_key: match value.get("state_key") { + Some(state_key_value) => match state_key_value.as_str() { + Some(state_key) => state_key.to_string(), + None => { + return Ok(EventResult::validation_error("field `state_key` must be a string".to_string(), value)); + } + }, + None => { + return Ok(EventResult::validation_error("missing field `state_key`".to_string(), value)); + } + }, + sender: match value.get("sender") { + Some(sender_value) => match sender_value.as_str() { + Some(sender_str) => match UserId::try_from(sender_str) { + Ok(sender) => sender, + Err(error) => { + return Ok(EventResult::validation_error(error.to_string(), value)); + } + }, + None => { + return Ok(EventResult::validation_error("field `sender` must be a string".to_string(), value)); + } + }, + None => { + return Ok(EventResult::validation_error("missing field `sender`".to_string(), value)); + } + }, + }) + } + // EventType::RoomAvatar => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomAvatar(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + // EventType::RoomCanonicalAlias => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomCanonicalAlias(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + // EventType::RoomCreate => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomCreate(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + // EventType::RoomGuestAccess => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomGuestAccess(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + // EventType::RoomHistoryVisibility => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomHistoryVisibility(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + // EventType::RoomJoinRules => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomJoinRules(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + // EventType::RoomMember => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomMember(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + // EventType::RoomName => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomName(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + // EventType::RoomPowerLevels => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomPowerLevels(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + // EventType::RoomThirdPartyInvite => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomThirdPartyInvite(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + // EventType::RoomTopic => match from_value::(value) { + // Ok(stripped_state) => StrippedState::RoomTopic(stripped_state), + // Err(error) => { + // return Ok(EventResult::Ok(InvalidEvent(InnerInvalidEvent::Validation { + // json: value, + // message: error.to_string(), + // }))) + // } + // }, + _ => return Ok(EventResult::Err(InvalidEvent(InnerInvalidEvent::Validation { + json: value, + message: "not a state event".to_string(), + }))), + }; + + Ok(EventResult::Ok(stripped_state)) + } } +// impl FromStr for StrippedState { +// type Err = InvalidEvent; + +// /// Attempt to create `Self` from parsing a string of JSON data. +// fn from_str(json: &str) -> Result { +// let value = match serde_json::from_str::(json) { +// Ok(value) => value, +// Err(error) => match serde_json::from_str::(json) { +// Ok(value) => { +// return Err(InvalidEvent(InnerInvalidEvent::Validation { +// json: value, +// message: error.to_string(), +// })); +// } +// Err(error) => { +// return Err(InvalidEvent(InnerInvalidEvent::Deserialization { error })); +// } +// }, +// }; + +// let event_type_value = match value.get("type") { +// Some(value) => value.clone(), +// None => { +// return Err(InvalidEvent(InnerInvalidEvent::Validation { +// json: value, +// message: "missing field `type`".to_string(), +// })) +// } +// }; + +// let event_type = match from_value::(event_type_value.clone()) { +// Ok(event_type) => event_type, +// Err(error) => { +// return Err(InvalidEvent(InnerInvalidEvent::Validation { +// json: value, +// message: error.to_string(), +// })) +// } +// }; + +// match event_type { +// EventType::RoomAliases => Ok(StrippedState::RoomAliases(json.parse()?)), +// EventType::RoomAvatar => Ok(StrippedState::RoomAvatar(json.parse()?)), +// EventType::RoomCanonicalAlias => Ok(StrippedState::RoomCanonicalAlias(json.parse()?)), +// EventType::RoomCreate => Ok(StrippedState::RoomCreate(json.parse()?)), +// EventType::RoomGuestAccess => Ok(StrippedState::RoomGuestAccess(json.parse()?)), +// EventType::RoomHistoryVisibility => { +// Ok(StrippedState::RoomHistoryVisibility(json.parse()?)) +// } +// EventType::RoomJoinRules => Ok(StrippedState::RoomJoinRules(json.parse()?)), +// EventType::RoomMember => Ok(StrippedState::RoomMember(json.parse()?)), +// EventType::RoomName => Ok(StrippedState::RoomName(json.parse()?)), +// EventType::RoomPowerLevels => Ok(StrippedState::RoomPowerLevels(json.parse()?)), +// EventType::RoomThirdPartyInvite => { +// Ok(StrippedState::RoomThirdPartyInvite(json.parse()?)) +// } +// EventType::RoomTopic => Ok(StrippedState::RoomTopic(json.parse()?)), +// _ => Err(InvalidEvent(InnerInvalidEvent::Validation { +// json: value, +// message: "not a state event".to_string(), +// })), +// } +// } +// } + +// impl<'a> TryFrom<&'a str> for StrippedState { +// type Error = InvalidEvent; + +// /// Attempt to create `Self` from parsing a string of JSON data. +// fn try_from(json: &'a str) -> Result { +// FromStr::from_str(json) +// } +// } + +impl Serialize for StrippedState { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + StrippedState::RoomAliases(ref event) => event.serialize(serializer), + StrippedState::RoomAvatar(ref event) => event.serialize(serializer), + StrippedState::RoomCanonicalAlias(ref event) => event.serialize(serializer), + StrippedState::RoomCreate(ref event) => event.serialize(serializer), + StrippedState::RoomGuestAccess(ref event) => event.serialize(serializer), + StrippedState::RoomHistoryVisibility(ref event) => event.serialize(serializer), + StrippedState::RoomJoinRules(ref event) => event.serialize(serializer), + StrippedState::RoomMember(ref event) => event.serialize(serializer), + StrippedState::RoomName(ref event) => event.serialize(serializer), + StrippedState::RoomPowerLevels(ref event) => event.serialize(serializer), + StrippedState::RoomThirdPartyInvite(ref event) => event.serialize(serializer), + StrippedState::RoomTopic(ref event) => event.serialize(serializer), + } + } +} + +// impl<'de, C> Deserialize<'de> for EventResult> +// where +// EventResult: Deserialize<'de>, +// { +// fn deserialize(deserializer: D) -> Result +// where +// D: Deserializer<'de>, +// { +// let value = serde_json::Value::deserialize(deserializer)?; + +// let event_type_value = match value.get("type") { +// Some(value) => value.clone(), +// None => { +// return Ok(EventResult::validation_error("missing field `type`".to_string(), value)) +// } +// }; + +// let event_type = match from_value::(event_type_value.clone()) { +// Ok(event_type) => event_type, +// Err(error) => { +// return Ok(EventResult::validation_error(error.to_string(), value)) +// } +// }; + +// let content = match value.get("content") { +// Some(content_value) => match content_value.as_object() { +// Some(content) => content, +// None => { +// return Ok(EventResult::validation_error("field `content` must be an object".to_string(), value)) +// } +// }, +// None => { +// return Ok(EventResult::validation_error("missing field `content`".to_string(), value)) +// } +// }; + +// match event_type { +// EventType::RoomAliases => stripped_state_content::(event_type, value), +// EventType::RoomAvatar => stripped_state_content(event_type, value), +// EventType::RoomCanonicalAlias => { +// stripped_state_content(event_type, value) +// } +// EventType::RoomCreate => stripped_state_content(event_type, value), +// EventType::RoomGuestAccess => stripped_state_content(event_type, value), +// EventType::RoomHistoryVisibility => { +// stripped_state_content(event_type, value) +// } +// EventType::RoomJoinRules => stripped_state_content(event_type, value), +// EventType::RoomMember => stripped_state_content(event_type, value), +// EventType::RoomName => stripped_state_content(event_type, value), +// EventType::RoomPowerLevels => stripped_state_content(event_type, value), +// EventType::RoomThirdPartyInvite => { +// stripped_state_content(event_type, value) +// } +// EventType::RoomTopic => stripped_state_content(event_type, value), +// _ => Ok(EventResult::validation_error("not a state event".to_string(), value)), +// } +// } +// } + +// impl FromStr for StrippedStateContent +// where +// C: FromStr, +// ::Err: ToString, +// { +// type Err = InvalidEvent; + +// /// Attempt to create `Self` from parsing a string of JSON data. +// fn from_str(json: &str) -> Result { +// let value = match serde_json::from_str::(json) { +// Ok(value) => value, +// Err(error) => match serde_json::from_str::(json) { +// Ok(value) => { +// return Err(InvalidEvent(InnerInvalidEvent::Validation { +// json: value, +// message: error.to_string(), +// })); +// } +// Err(error) => { +// return Err(InvalidEvent(InnerInvalidEvent::Deserialization { error })); +// } +// }, +// }; + +// let event_type_value = match value.get("type") { +// Some(value) => value.clone(), +// None => { +// return Err(InvalidEvent(InnerInvalidEvent::Validation { +// json: value, +// message: "missing field `type`".to_string(), +// })) +// } +// }; + +// let event_type = match from_value::(event_type_value.clone()) { +// Ok(event_type) => event_type, +// Err(error) => { +// return Err(InvalidEvent(InnerInvalidEvent::Validation { +// json: value, +// message: error.to_string(), +// })) +// } +// }; + +// let content = match value.get("content") { +// Some(content_value) => match content_value.as_object() { +// Some(content) => content, +// None => { +// return Err(InvalidEvent(InnerInvalidEvent::Validation { +// json: value, +// message: "field `content` must be an object".to_string(), +// })) +// } +// }, +// None => { +// return Err(InvalidEvent(InnerInvalidEvent::Validation { +// json: value, +// message: "missing field `content`".to_string(), +// })) +// } +// }; + +// // Unwrap is safe because we already know this can deserialize to a `Value`. +// let json_string = to_string(content).unwrap(); + +// match event_type { +// EventType::RoomAliases => stripped_state_content(&json_string, event_type, value), +// EventType::RoomAvatar => stripped_state_content(&json_string, event_type, value), +// EventType::RoomCanonicalAlias => { +// stripped_state_content(&json_string, event_type, value) +// } +// EventType::RoomCreate => stripped_state_content(&json_string, event_type, value), +// EventType::RoomGuestAccess => stripped_state_content(&json_string, event_type, value), +// EventType::RoomHistoryVisibility => { +// stripped_state_content(&json_string, event_type, value) +// } +// EventType::RoomJoinRules => stripped_state_content(&json_string, event_type, value), +// EventType::RoomMember => stripped_state_content(&json_string, event_type, value), +// EventType::RoomName => stripped_state_content(&json_string, event_type, value), +// EventType::RoomPowerLevels => stripped_state_content(&json_string, event_type, value), +// EventType::RoomThirdPartyInvite => { +// stripped_state_content(&json_string, event_type, value) +// } +// EventType::RoomTopic => stripped_state_content(&json_string, event_type, value), +// _ => Err(InvalidEvent(InnerInvalidEvent::Validation { +// json: value, +// message: "not a state event".to_string(), +// })), +// } +// } +// } + +// impl<'a, C> TryFrom<&'a str> for StrippedStateContent +// where +// C: FromStr, +// ::Err: ToString, +// { +// type Error = InvalidEvent; + +// /// Attempt to create `Self` from parsing a string of JSON data. +// fn try_from(json: &'a str) -> Result { +// FromStr::from_str(json) +// } +// } + +// /// Reduces the boilerplate in the match arms of `impl Deserialize for StrippedState`. +// #[inline] +// fn create_stripped_state( +// event_type: EventType, +// value: Value, +// ) -> Result, serde_json::Error> +// where +// for<'de> EventResult: Deserialize<'de>, +// { +// let event_result = from_value::>(value)?; + +// Ok(EventResult::Ok(StrippedStateContent { +// content: event_result.into_result().unwrap(), +// event_type, +// state_key: match value.get("state_key") { +// Some(state_key_value) => match state_key_value.as_str() { +// Some(state_key) => state_key.to_string(), +// None => { +// return Ok(EventResult::validation_error("field `state_key` must be a string".to_string(), value)); +// } +// }, +// None => { +// return Ok(EventResult::validation_error("missing field `state_key`".to_string(), value)); +// } +// }, +// sender: match value.get("sender") { +// Some(sender_value) => match sender_value.as_str() { +// Some(sender_str) => match UserId::try_from(sender_str) { +// Ok(sender) => sender, +// Err(error) => { +// return Ok(EventResult::validation_error(error.to_string(), value)); +// } +// }, +// None => { +// return Ok(EventResult::validation_error("field `sender` must be a string".to_string(), value)); +// } +// }, +// None => { +// return Ok(EventResult::validation_error("missing field `sender`".to_string(), value)); +// } +// }, +// })) +// } + #[cfg(test)] mod tests { use std::convert::TryFrom;