This commit is contained in:
Jimmy Cuadra 2019-09-03 12:01:29 -07:00
parent c309eed2ae
commit 91d564dcf8
3 changed files with 618 additions and 324 deletions

View File

@ -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]

View File

@ -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<T> EventResult<T> {
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<HashMap<K, V>>
where
K: for<'inner> Deserialize<'inner> + Eq + Hash,
V: for<'inner> Deserialize<'inner>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
let hash_map: HashMap<K, V> = 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<Empty> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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<Self>: Deserialize<'de>,
for<'de> EventResult<Self::Content>: 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<Self>: Deserialize<'de>,
for<'de> EventResult<<Self as Event>::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<Self>: Deserialize<'de>,
for<'de> EventResult<<Self as Event>::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> {

View File

@ -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<C> {
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<Self, Self::Err> {
let value = match serde_json::from_str::<Value>(json) {
Ok(value) => value,
Err(error) => match serde_json::from_str::<serde_json::Value>(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::<EventType>(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<Self, Self::Error> {
FromStr::from_str(json)
}
}
impl Serialize for StrippedState {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<C> FromStr for StrippedStateContent<C>
where
C: FromStr,
<C as FromStr>::Err: ToString,
{
type Err = InvalidEvent;
/// Attempt to create `Self` from parsing a string of JSON data.
fn from_str(json: &str) -> Result<Self, Self::Err> {
let value = match serde_json::from_str::<Value>(json) {
Ok(value) => value,
Err(error) => match serde_json::from_str::<serde_json::Value>(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::<EventType>(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<C>
where
C: FromStr,
<C as FromStr>::Err: ToString,
{
type Error = InvalidEvent;
/// Attempt to create `Self` from parsing a string of JSON data.
fn try_from(json: &'a str) -> Result<Self, Self::Error> {
FromStr::from_str(json)
}
}
/// A stripped-down version of the *m.room.aliases* event.
pub type StrippedRoomAliases = StrippedStateContent<AliasesEventContent>;
@ -318,75 +117,499 @@ pub type StrippedRoomThirdPartyInvite = StrippedStateContent<ThirdPartyInviteEve
/// A stripped-down version of the *m.room.topic* event.
pub type StrippedRoomTopic = StrippedStateContent<TopicEventContent>;
/// Reduces the boilerplate in the match arms of `impl FromStr for StrippedState`.
#[inline]
fn stripped_state_content<C>(
json: &str,
event_type: EventType,
value: Value,
) -> Result<StrippedStateContent<C>, InvalidEvent>
where
C: FromStr,
<C as FromStr>::Err: ToString,
{
let content = match json.parse::<C>() {
Ok(content) => content,
Err(error) => {
return Err(InvalidEvent(InnerInvalidEvent::Validation {
json: value,
message: error.to_string(),
}))
}
};
impl<'de> Deserialize<'de> for EventResult<StrippedState> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
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::<EventType>(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::<EventResult<AliasesEventContent>>(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::<StrippedRoomAvatar>(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::<StrippedRoomCanonicalAlias>(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::<StrippedRoomCreate>(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::<StrippedRoomGuestAccess>(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::<StrippedRoomHistoryVisibility>(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::<StrippedRoomJoinRules>(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::<StrippedRoomMember>(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::<StrippedRoomName>(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::<StrippedRoomPowerLevels>(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::<StrippedRoomThirdPartyInvite>(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::<StrippedRoomTopic>(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<Self, Self::Err> {
// let value = match serde_json::from_str::<Value>(json) {
// Ok(value) => value,
// Err(error) => match serde_json::from_str::<serde_json::Value>(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::<EventType>(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<Self, Self::Error> {
// FromStr::from_str(json)
// }
// }
impl Serialize for StrippedState {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<StrippedStateContent<C>>
// where
// EventResult<C>: Deserialize<'de>,
// {
// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
// 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::<EventType>(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::<AliasesEventContent>(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<C> FromStr for StrippedStateContent<C>
// where
// C: FromStr,
// <C as FromStr>::Err: ToString,
// {
// type Err = InvalidEvent;
// /// Attempt to create `Self` from parsing a string of JSON data.
// fn from_str(json: &str) -> Result<Self, Self::Err> {
// let value = match serde_json::from_str::<Value>(json) {
// Ok(value) => value,
// Err(error) => match serde_json::from_str::<serde_json::Value>(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::<EventType>(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<C>
// where
// C: FromStr,
// <C as FromStr>::Err: ToString,
// {
// type Error = InvalidEvent;
// /// Attempt to create `Self` from parsing a string of JSON data.
// fn try_from(json: &'a str) -> Result<Self, Self::Error> {
// 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<EventResult<StrippedState>, serde_json::Error>
// where
// for<'de> EventResult<C>: Deserialize<'de>,
// {
// let event_result = from_value::<EventResult<C>>(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;