This commit is contained in:
Jonas Platte 2019-09-28 01:17:38 +02:00
parent 297bae4cbb
commit 05562a48a3
24 changed files with 1553 additions and 1109 deletions

View File

@ -14,7 +14,7 @@ edition = "2018"
[dependencies]
ruma-identifiers = "0.14.0"
ruma-events-macros = { version = "0.1.0", path = "ruma-events-macros" }
ruma-events-macros = { path = "ruma-events-macros" }
serde_json = "1.0.40"
[dependencies.js_int]

View File

@ -164,24 +164,11 @@ impl ToTokens for RumaEvent {
let try_from_field_value = if ident == "content" {
match &self.content {
Content::Struct(content_fields) => {
let mut content_field_values: Vec<TokenStream> =
Vec::with_capacity(content_fields.len());
for content_field in content_fields {
let content_field_ident = content_field.ident.clone().unwrap();
let span = content_field.span();
let token_stream = quote_spanned! {span=>
#content_field_ident: raw.content.#content_field_ident,
};
content_field_values.push(token_stream);
}
Content::Struct(_) => {
quote_spanned! {span=>
content: #content_name {
#(#content_field_values)*
content: match std::convert::TryFrom::try_from(raw.content) {
Ok(c) => c,
Err((_, void)) => match void {},
},
}
}
@ -193,25 +180,12 @@ impl ToTokens for RumaEvent {
}
} else if ident == "prev_content" {
match &self.content {
Content::Struct(content_fields) => {
let mut content_field_values: Vec<TokenStream> =
Vec::with_capacity(content_fields.len());
for content_field in content_fields {
let content_field_ident = content_field.ident.clone().unwrap();
let span = content_field.span();
let token_stream = quote_spanned! {span=>
#content_field_ident: prev.#content_field_ident,
};
content_field_values.push(token_stream);
}
Content::Struct(_) => {
quote_spanned! {span=>
prev_content: raw.prev_content.map(|prev| {
#content_name {
#(#content_field_values)*
prev_content: raw.prev_content.map(|prev_content| {
match std::convert::TryFrom::try_from(prev_content) {
Ok(c) => c,
Err((_, void)) => match void {},
}
}),
}
@ -360,31 +334,19 @@ impl ToTokens for RumaEvent {
}
quote! {
impl<'de> serde::Deserialize<'de> for crate::EventResult<#content_name> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
impl std::convert::TryFrom<raw::#content_name> for #content_name {
type Error = (raw::#content_name, crate::Void);
let raw: raw::#content_name = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(crate::EventResult::Err(crate::InvalidEvent(
crate::InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(crate::EventResult::Ok(#content_name {
fn try_from(raw: raw::#content_name) -> Result<Self, Self::Error> {
Ok(Self {
#(#content_field_values)*
}))
})
}
}
impl crate::EventResultCompatible for #content_name {
type Raw = raw::#content_name;
}
}
} else {
TokenStream::new()
@ -399,36 +361,25 @@ impl ToTokens for RumaEvent {
#content
impl<'de> serde::Deserialize<'de> for crate::EventResult<#name> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
impl std::convert::TryFrom<raw::#name> for #name {
type Error = (raw::#name, crate::Void);
let raw: raw::#name = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(crate::EventResult::Err(crate::InvalidEvent(
crate::InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(crate::EventResult::Ok(#name {
fn try_from(raw: raw::#name) -> Result<Self, Self::Error> {
Ok(Self {
#(#try_from_field_values)*
}))
})
}
}
impl crate::EventResultCompatible for #name {
type Raw = raw::#name;
}
#impl_conversions_for_content
use serde::ser::SerializeStruct as _;
impl serde::Serialize for #name {
impl serde::Serialize for #name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer
@ -464,7 +415,7 @@ impl ToTokens for RumaEvent {
#impl_state_event
/// "Raw" versions of the event and its content which implement `serde::Deserialize`.
mod raw {
pub(crate) mod raw {
use super::*;
#(#attrs)*

View File

@ -1,4 +1,7 @@
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::{
fmt::{Debug, Display, Formatter, Result as FmtResult},
marker::PhantomData,
};
use serde::{
de::{Error as SerdeError, Visitor},
@ -82,19 +85,19 @@ 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> {
pub enum EventResult<T: EventResultCompatible> {
/// `T` deserialized and validated successfully.
Ok(T),
/// `T` deserialized but was invalid.
///
/// `InvalidEvent` contains the original input.
Err(InvalidEvent),
Err(InvalidEvent<T::Raw>),
}
impl<T> EventResult<T> {
/// Convert `EventResult<T>` into the equivalent `std::result::Result<T, InvalidEvent>`.
pub fn into_result(self) -> Result<T, InvalidEvent> {
impl<T: EventResultCompatible> EventResult<T> {
/// Convert `EventResult<T>` into the equivalent `std::result::Result<T, InvalidEvent<T::Raw>>`.
pub fn into_result(self) -> Result<T, InvalidEvent<T::Raw>> {
match self {
EventResult::Ok(t) => Ok(t),
EventResult::Err(invalid_event) => Err(invalid_event),
@ -102,11 +105,21 @@ impl<T> EventResult<T> {
}
}
pub trait EventResultCompatible {
/// The raw form of this event that deserialization falls back to if deserializing `Self` fails.
type Raw;
}
enum Void {}
impl From<Void> for String {
fn from(v: Void) -> Self {
match v {}
}
}
/// A basic event.
pub trait Event
where
Self: Debug + Serialize,
{
pub trait Event: Debug + Serialize + EventResultCompatible {
/// The type of this event's `content` field.
type Content: Debug + Serialize;
@ -157,11 +170,11 @@ pub trait StateEvent: RoomEvent {
/// 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(InnerInvalidEvent);
pub struct InvalidEvent<T>(InnerInvalidEvent<T>);
/// An event that is malformed or otherwise invalid.
#[derive(Debug)]
enum InnerInvalidEvent {
enum InnerInvalidEvent<T> {
/// An event that deserialized but failed validation.
Validation {
/// The raw `serde_json::Value` representation of the invalid event.
@ -169,6 +182,8 @@ enum InnerInvalidEvent {
/// An message describing why the event was invalid.
message: String,
dummy: PhantomData<T>,
},
}

View File

@ -1,9 +1,11 @@
//! Enums for heterogeneous collections of events, inclusive for every event type that implements
//! the trait of the same name.
use serde::{Serialize, Serializer};
use serde_json::{from_value, Value};
use std::convert::TryFrom;
use serde::{Serialize, Serializer};
use super::raw::all as raw;
use crate::{
call::{
answer::AnswerEvent, candidates::CandidatesEvent, hangup::HangupEvent, invite::InviteEvent,
@ -46,7 +48,7 @@ use crate::{
sticker::StickerEvent,
tag::TagEvent,
typing::TypingEvent,
CustomEvent, CustomRoomEvent, CustomStateEvent, EventType, InnerInvalidEvent, InvalidEvent,
CustomEvent, CustomRoomEvent, CustomStateEvent, EventResultCompatible, Void,
};
/// A basic event, room event, or state event.
@ -334,6 +336,42 @@ pub enum StateEvent {
CustomState(CustomStateEvent),
}
impl EventResultCompatible for Event {
type Raw = raw::Event;
}
impl TryFrom<raw::Event> for Event {
type Error = (raw::Event, Void);
fn try_from(raw: raw::Event) -> Result<Self, Self::Error> {
unimplemented!()
}
}
impl EventResultCompatible for RoomEvent {
type Raw = raw::RoomEvent;
}
impl TryFrom<raw::RoomEvent> for RoomEvent {
type Error = (raw::RoomEvent, Void);
fn try_from(raw: raw::RoomEvent) -> Result<Self, Self::Error> {
unimplemented!()
}
}
impl EventResultCompatible for StateEvent {
type Raw = raw::StateEvent;
}
impl TryFrom<raw::StateEvent> for StateEvent {
type Error = (raw::StateEvent, Void);
fn try_from(raw: raw::StateEvent) -> Result<Self, Self::Error> {
unimplemented!()
}
}
impl Serialize for Event {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where

View File

@ -1,12 +1,11 @@
//! Enums for heterogeneous collections of events, exclusive to event types that implement "at
//! most" the trait of the same name.
use std::str::FromStr;
use std::convert::TryFrom;
use serde::{Serialize, Serializer};
use serde_json::{from_value, Value};
pub use super::all::StateEvent;
pub use super::{all::StateEvent, raw::only as raw};
use crate::{
call::{
answer::AnswerEvent, candidates::CandidatesEvent, hangup::HangupEvent, invite::InviteEvent,
@ -33,7 +32,7 @@ use crate::{
sticker::StickerEvent,
tag::TagEvent,
typing::TypingEvent,
CustomEvent, CustomRoomEvent, EventType, InnerInvalidEvent, InvalidEvent,
CustomEvent, CustomRoomEvent, EventResultCompatible, Void,
};
/// A basic event.
@ -133,6 +132,30 @@ pub enum RoomEvent {
CustomRoom(CustomRoomEvent),
}
impl EventResultCompatible for Event {
type Raw = raw::Event;
}
impl TryFrom<raw::Event> for Event {
type Error = (raw::Event, Void);
fn try_from(raw: raw::Event) -> Result<Self, Self::Error> {
unimplemented!()
}
}
impl EventResultCompatible for RoomEvent {
type Raw = raw::RoomEvent;
}
impl TryFrom<raw::RoomEvent> for RoomEvent {
type Error = (raw::RoomEvent, Void);
fn try_from(raw: raw::RoomEvent) -> Result<Self, Self::Error> {
unimplemented!()
}
}
impl Serialize for Event {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where

604
src/collections/raw/all.rs Normal file
View File

@ -0,0 +1,604 @@
//! Enums for heterogeneous collections of events, inclusive for every event type that implements
//! the trait of the same name.
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{
call::{
answer::AnswerEvent, candidates::CandidatesEvent, hangup::HangupEvent, invite::InviteEvent,
},
direct::DirectEvent,
dummy::DummyEvent,
forwarded_room_key::ForwardedRoomKeyEvent,
fully_read::FullyReadEvent,
ignored_user_list::IgnoredUserListEvent,
key::verification::{
accept::AcceptEvent, cancel::CancelEvent, key::KeyEvent, mac::MacEvent,
request::RequestEvent, start::StartEvent,
},
presence::PresenceEvent,
push_rules::PushRulesEvent,
receipt::ReceiptEvent,
room::{
aliases::AliasesEvent,
avatar::AvatarEvent,
canonical_alias::CanonicalAliasEvent,
create::CreateEvent,
encrypted::EncryptedEvent,
encryption::EncryptionEvent,
guest_access::GuestAccessEvent,
history_visibility::HistoryVisibilityEvent,
join_rules::JoinRulesEvent,
member::MemberEvent,
message::{feedback::FeedbackEvent, MessageEvent},
name::NameEvent,
pinned_events::PinnedEventsEvent,
power_levels::PowerLevelsEvent,
redaction::RedactionEvent,
server_acl::ServerAclEvent,
third_party_invite::ThirdPartyInviteEvent,
tombstone::TombstoneEvent,
topic::TopicEvent,
},
room_key::RoomKeyEvent,
room_key_request::RoomKeyRequestEvent,
sticker::StickerEvent,
tag::TagEvent,
typing::TypingEvent,
CustomEvent, CustomRoomEvent, CustomStateEvent,
};
/// A basic event, room event, or state event.
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum Event {
/// m.call.answer
CallAnswer(AnswerEvent),
/// m.call.candidates
CallCandidates(CandidatesEvent),
/// m.call.hangup
CallHangup(HangupEvent),
/// m.call.invite
CallInvite(InviteEvent),
/// m.direct
Direct(DirectEvent),
/// m.dummy
Dummy(DummyEvent),
/// m.forwarded_room_key
ForwardedRoomKey(ForwardedRoomKeyEvent),
/// m.fully_read
FullyRead(FullyReadEvent),
/// m.ignored_user_list
IgnoredUserList(IgnoredUserListEvent),
/// m.key.verification.accept
KeyVerificationAccept(AcceptEvent),
/// m.key.verification.cancel
KeyVerificationCancel(CancelEvent),
/// m.key.verification.key
KeyVerificationKey(KeyEvent),
/// m.key.verification.mac
KeyVerificationMac(MacEvent),
/// m.key.verification.request
KeyVerificationRequest(RequestEvent),
/// m.key.verification.start
KeyVerificationStart(StartEvent),
/// m.presence
Presence(PresenceEvent),
/// m.push_rules
PushRules(PushRulesEvent),
/// m.receipt
Receipt(ReceiptEvent),
/// m.room.aliases
RoomAliases(AliasesEvent),
/// m.room.avatar
RoomAvatar(AvatarEvent),
/// m.room.canonical_alias
RoomCanonicalAlias(CanonicalAliasEvent),
/// m.room.create
RoomCreate(CreateEvent),
/// m.room.encrypted
RoomEncrypted(EncryptedEvent),
/// m.room.encryption
RoomEncryption(EncryptionEvent),
/// m.room.guest_access
RoomGuestAccess(GuestAccessEvent),
/// m.room.history_visibility
RoomHistoryVisibility(HistoryVisibilityEvent),
/// m.room.join_rules
RoomJoinRules(JoinRulesEvent),
/// m.room.member
RoomMember(MemberEvent),
/// m.room.message
RoomMessage(MessageEvent),
/// m.room.message.feedback
RoomMessageFeedback(FeedbackEvent),
/// m.room.name
RoomName(NameEvent),
/// m.room.pinned_events
RoomPinnedEvents(PinnedEventsEvent),
/// m.room.power_levels
RoomPowerLevels(PowerLevelsEvent),
/// m.room.redaction
RoomRedaction(RedactionEvent),
/// m.room.server_acl,
RoomServerAcl(ServerAclEvent),
/// m.room.third_party_invite
RoomThirdPartyInvite(ThirdPartyInviteEvent),
/// m.room.tombstone
RoomTombstone(TombstoneEvent),
/// m.room.topic
RoomTopic(TopicEvent),
/// m.room_key
RoomKey(RoomKeyEvent),
/// m.room_key_request
RoomKeyRequest(RoomKeyRequestEvent),
/// m.sticker
Sticker(StickerEvent),
/// m.tag
Tag(TagEvent),
/// m.typing
Typing(TypingEvent),
/// Any basic event that is not part of the specification.
Custom(CustomEvent),
/// Any room event that is not part of the specification.
CustomRoom(CustomRoomEvent),
/// Any state event that is not part of the specification.
CustomState(CustomStateEvent),
}
/// A room event or state event.
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum RoomEvent {
/// m.call.answer
CallAnswer(AnswerEvent),
/// m.call.candidates
CallCandidates(CandidatesEvent),
/// m.call.hangup
CallHangup(HangupEvent),
/// m.call.invite
CallInvite(InviteEvent),
/// m.room.aliases
RoomAliases(AliasesEvent),
/// m.room.avatar
RoomAvatar(AvatarEvent),
/// m.room.canonical_alias
RoomCanonicalAlias(CanonicalAliasEvent),
/// m.room.create
RoomCreate(CreateEvent),
/// m.room.encrypted
RoomEncrypted(EncryptedEvent),
/// m.room.encryption
RoomEncryption(EncryptionEvent),
/// m.room.guest_access
RoomGuestAccess(GuestAccessEvent),
/// m.room.history_visibility
RoomHistoryVisibility(HistoryVisibilityEvent),
/// m.room.join_rules
RoomJoinRules(JoinRulesEvent),
/// m.room.member
RoomMember(MemberEvent),
/// m.room.message
RoomMessage(MessageEvent),
/// m.room.message.feedback
RoomMessageFeedback(FeedbackEvent),
/// m.room.name
RoomName(NameEvent),
/// m.room.pinned_events
RoomPinnedEvents(PinnedEventsEvent),
/// m.room.power_levels
RoomPowerLevels(PowerLevelsEvent),
/// m.room.redaction
RoomRedaction(RedactionEvent),
/// m.room.server_acl,
RoomServerAcl(ServerAclEvent),
/// m.room.third_party_invite
RoomThirdPartyInvite(ThirdPartyInviteEvent),
/// m.room.tombstone
RoomTombstone(TombstoneEvent),
/// m.room.topic
RoomTopic(TopicEvent),
/// m.sticker
Sticker(StickerEvent),
/// Any room event that is not part of the specification.
CustomRoom(CustomRoomEvent),
/// Any state event that is not part of the specification.
CustomState(CustomStateEvent),
}
/// A state event.
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum StateEvent {
/// m.room.aliases
RoomAliases(AliasesEvent),
/// m.room.avatar
RoomAvatar(AvatarEvent),
/// m.room.canonical_alias
RoomCanonicalAlias(CanonicalAliasEvent),
/// m.room.create
RoomCreate(CreateEvent),
/// m.room.encryption
RoomEncryption(EncryptionEvent),
/// m.room.guest_access
RoomGuestAccess(GuestAccessEvent),
/// m.room.history_visibility
RoomHistoryVisibility(HistoryVisibilityEvent),
/// m.room.join_rules
RoomJoinRules(JoinRulesEvent),
/// m.room.member
RoomMember(MemberEvent),
/// m.room.name
RoomName(NameEvent),
/// m.room.pinned_events
RoomPinnedEvents(PinnedEventsEvent),
/// m.room.power_levels
RoomPowerLevels(PowerLevelsEvent),
/// m.room.server_acl,
RoomServerAcl(ServerAclEvent),
/// m.room.third_party_invite
RoomThirdPartyInvite(ThirdPartyInviteEvent),
/// m.room.tombstone
RoomTombstone(TombstoneEvent),
/// m.room.topic
RoomTopic(TopicEvent),
/// Any state event that is not part of the specification.
CustomState(CustomStateEvent),
}
impl<'de> Deserialize<'de> for Event {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
unimplemented!()
}
}
impl<'de> Deserialize<'de> for RoomEvent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
unimplemented!()
}
}
impl<'de> Deserialize<'de> for StateEvent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
unimplemented!()
}
}
impl Serialize for Event {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Event::CallAnswer(ref event) => event.serialize(serializer),
Event::CallCandidates(ref event) => event.serialize(serializer),
Event::CallHangup(ref event) => event.serialize(serializer),
Event::CallInvite(ref event) => event.serialize(serializer),
Event::Direct(ref event) => event.serialize(serializer),
Event::Dummy(ref event) => event.serialize(serializer),
Event::ForwardedRoomKey(ref event) => event.serialize(serializer),
Event::FullyRead(ref event) => event.serialize(serializer),
Event::KeyVerificationAccept(ref event) => event.serialize(serializer),
Event::KeyVerificationCancel(ref event) => event.serialize(serializer),
Event::KeyVerificationKey(ref event) => event.serialize(serializer),
Event::KeyVerificationMac(ref event) => event.serialize(serializer),
Event::KeyVerificationRequest(ref event) => event.serialize(serializer),
Event::KeyVerificationStart(ref event) => event.serialize(serializer),
Event::IgnoredUserList(ref event) => event.serialize(serializer),
Event::Presence(ref event) => event.serialize(serializer),
Event::PushRules(ref event) => event.serialize(serializer),
Event::Receipt(ref event) => event.serialize(serializer),
Event::RoomAliases(ref event) => event.serialize(serializer),
Event::RoomAvatar(ref event) => event.serialize(serializer),
Event::RoomCanonicalAlias(ref event) => event.serialize(serializer),
Event::RoomCreate(ref event) => event.serialize(serializer),
Event::RoomEncrypted(ref event) => event.serialize(serializer),
Event::RoomEncryption(ref event) => event.serialize(serializer),
Event::RoomGuestAccess(ref event) => event.serialize(serializer),
Event::RoomHistoryVisibility(ref event) => event.serialize(serializer),
Event::RoomJoinRules(ref event) => event.serialize(serializer),
Event::RoomMember(ref event) => event.serialize(serializer),
Event::RoomMessage(ref event) => event.serialize(serializer),
Event::RoomMessageFeedback(ref event) => event.serialize(serializer),
Event::RoomName(ref event) => event.serialize(serializer),
Event::RoomPinnedEvents(ref event) => event.serialize(serializer),
Event::RoomPowerLevels(ref event) => event.serialize(serializer),
Event::RoomRedaction(ref event) => event.serialize(serializer),
Event::RoomServerAcl(ref event) => event.serialize(serializer),
Event::RoomThirdPartyInvite(ref event) => event.serialize(serializer),
Event::RoomTombstone(ref event) => event.serialize(serializer),
Event::RoomTopic(ref event) => event.serialize(serializer),
Event::RoomKey(ref event) => event.serialize(serializer),
Event::RoomKeyRequest(ref event) => event.serialize(serializer),
Event::Sticker(ref event) => event.serialize(serializer),
Event::Tag(ref event) => event.serialize(serializer),
Event::Typing(ref event) => event.serialize(serializer),
Event::Custom(ref event) => event.serialize(serializer),
Event::CustomRoom(ref event) => event.serialize(serializer),
Event::CustomState(ref event) => event.serialize(serializer),
}
}
}
impl Serialize for RoomEvent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
RoomEvent::CallAnswer(ref event) => event.serialize(serializer),
RoomEvent::CallCandidates(ref event) => event.serialize(serializer),
RoomEvent::CallHangup(ref event) => event.serialize(serializer),
RoomEvent::CallInvite(ref event) => event.serialize(serializer),
RoomEvent::RoomAliases(ref event) => event.serialize(serializer),
RoomEvent::RoomAvatar(ref event) => event.serialize(serializer),
RoomEvent::RoomCanonicalAlias(ref event) => event.serialize(serializer),
RoomEvent::RoomCreate(ref event) => event.serialize(serializer),
RoomEvent::RoomEncrypted(ref event) => event.serialize(serializer),
RoomEvent::RoomEncryption(ref event) => event.serialize(serializer),
RoomEvent::RoomGuestAccess(ref event) => event.serialize(serializer),
RoomEvent::RoomHistoryVisibility(ref event) => event.serialize(serializer),
RoomEvent::RoomJoinRules(ref event) => event.serialize(serializer),
RoomEvent::RoomMember(ref event) => event.serialize(serializer),
RoomEvent::RoomMessage(ref event) => event.serialize(serializer),
RoomEvent::RoomMessageFeedback(ref event) => event.serialize(serializer),
RoomEvent::RoomName(ref event) => event.serialize(serializer),
RoomEvent::RoomPinnedEvents(ref event) => event.serialize(serializer),
RoomEvent::RoomPowerLevels(ref event) => event.serialize(serializer),
RoomEvent::RoomRedaction(ref event) => event.serialize(serializer),
RoomEvent::RoomServerAcl(ref event) => event.serialize(serializer),
RoomEvent::RoomThirdPartyInvite(ref event) => event.serialize(serializer),
RoomEvent::RoomTombstone(ref event) => event.serialize(serializer),
RoomEvent::RoomTopic(ref event) => event.serialize(serializer),
RoomEvent::Sticker(ref event) => event.serialize(serializer),
RoomEvent::CustomRoom(ref event) => event.serialize(serializer),
RoomEvent::CustomState(ref event) => event.serialize(serializer),
}
}
}
impl Serialize for StateEvent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
StateEvent::RoomAliases(ref event) => event.serialize(serializer),
StateEvent::RoomAvatar(ref event) => event.serialize(serializer),
StateEvent::RoomCanonicalAlias(ref event) => event.serialize(serializer),
StateEvent::RoomCreate(ref event) => event.serialize(serializer),
StateEvent::RoomEncryption(ref event) => event.serialize(serializer),
StateEvent::RoomGuestAccess(ref event) => event.serialize(serializer),
StateEvent::RoomHistoryVisibility(ref event) => event.serialize(serializer),
StateEvent::RoomJoinRules(ref event) => event.serialize(serializer),
StateEvent::RoomMember(ref event) => event.serialize(serializer),
StateEvent::RoomName(ref event) => event.serialize(serializer),
StateEvent::RoomPinnedEvents(ref event) => event.serialize(serializer),
StateEvent::RoomPowerLevels(ref event) => event.serialize(serializer),
StateEvent::RoomServerAcl(ref event) => event.serialize(serializer),
StateEvent::RoomThirdPartyInvite(ref event) => event.serialize(serializer),
StateEvent::RoomTombstone(ref event) => event.serialize(serializer),
StateEvent::RoomTopic(ref event) => event.serialize(serializer),
StateEvent::CustomState(ref event) => event.serialize(serializer),
}
}
}
macro_rules! impl_from_t_for_event {
($ty:ty, $variant:ident) => {
impl From<$ty> for Event {
fn from(event: $ty) -> Self {
Event::$variant(event)
}
}
};
}
impl_from_t_for_event!(AnswerEvent, CallAnswer);
impl_from_t_for_event!(CandidatesEvent, CallCandidates);
impl_from_t_for_event!(HangupEvent, CallHangup);
impl_from_t_for_event!(InviteEvent, CallInvite);
impl_from_t_for_event!(DirectEvent, Direct);
impl_from_t_for_event!(DummyEvent, Dummy);
impl_from_t_for_event!(ForwardedRoomKeyEvent, ForwardedRoomKey);
impl_from_t_for_event!(FullyReadEvent, FullyRead);
impl_from_t_for_event!(AcceptEvent, KeyVerificationAccept);
impl_from_t_for_event!(CancelEvent, KeyVerificationCancel);
impl_from_t_for_event!(KeyEvent, KeyVerificationKey);
impl_from_t_for_event!(MacEvent, KeyVerificationMac);
impl_from_t_for_event!(RequestEvent, KeyVerificationRequest);
impl_from_t_for_event!(StartEvent, KeyVerificationStart);
impl_from_t_for_event!(IgnoredUserListEvent, IgnoredUserList);
impl_from_t_for_event!(PresenceEvent, Presence);
impl_from_t_for_event!(PushRulesEvent, PushRules);
impl_from_t_for_event!(ReceiptEvent, Receipt);
impl_from_t_for_event!(AliasesEvent, RoomAliases);
impl_from_t_for_event!(AvatarEvent, RoomAvatar);
impl_from_t_for_event!(CanonicalAliasEvent, RoomCanonicalAlias);
impl_from_t_for_event!(CreateEvent, RoomCreate);
impl_from_t_for_event!(EncryptedEvent, RoomEncrypted);
impl_from_t_for_event!(EncryptionEvent, RoomEncryption);
impl_from_t_for_event!(GuestAccessEvent, RoomGuestAccess);
impl_from_t_for_event!(HistoryVisibilityEvent, RoomHistoryVisibility);
impl_from_t_for_event!(JoinRulesEvent, RoomJoinRules);
impl_from_t_for_event!(MemberEvent, RoomMember);
impl_from_t_for_event!(MessageEvent, RoomMessage);
impl_from_t_for_event!(FeedbackEvent, RoomMessageFeedback);
impl_from_t_for_event!(NameEvent, RoomName);
impl_from_t_for_event!(PinnedEventsEvent, RoomPinnedEvents);
impl_from_t_for_event!(PowerLevelsEvent, RoomPowerLevels);
impl_from_t_for_event!(RedactionEvent, RoomRedaction);
impl_from_t_for_event!(ServerAclEvent, RoomServerAcl);
impl_from_t_for_event!(ThirdPartyInviteEvent, RoomThirdPartyInvite);
impl_from_t_for_event!(TombstoneEvent, RoomTombstone);
impl_from_t_for_event!(TopicEvent, RoomTopic);
impl_from_t_for_event!(RoomKeyEvent, RoomKey);
impl_from_t_for_event!(RoomKeyRequestEvent, RoomKeyRequest);
impl_from_t_for_event!(StickerEvent, Sticker);
impl_from_t_for_event!(TagEvent, Tag);
impl_from_t_for_event!(TypingEvent, Typing);
impl_from_t_for_event!(CustomEvent, Custom);
impl_from_t_for_event!(CustomRoomEvent, CustomRoom);
impl_from_t_for_event!(CustomStateEvent, CustomState);
macro_rules! impl_from_t_for_room_event {
($ty:ty, $variant:ident) => {
impl From<$ty> for RoomEvent {
fn from(event: $ty) -> Self {
RoomEvent::$variant(event)
}
}
};
}
impl_from_t_for_room_event!(AnswerEvent, CallAnswer);
impl_from_t_for_room_event!(CandidatesEvent, CallCandidates);
impl_from_t_for_room_event!(HangupEvent, CallHangup);
impl_from_t_for_room_event!(InviteEvent, CallInvite);
impl_from_t_for_room_event!(AliasesEvent, RoomAliases);
impl_from_t_for_room_event!(AvatarEvent, RoomAvatar);
impl_from_t_for_room_event!(CanonicalAliasEvent, RoomCanonicalAlias);
impl_from_t_for_room_event!(CreateEvent, RoomCreate);
impl_from_t_for_room_event!(EncryptedEvent, RoomEncrypted);
impl_from_t_for_room_event!(EncryptionEvent, RoomEncryption);
impl_from_t_for_room_event!(GuestAccessEvent, RoomGuestAccess);
impl_from_t_for_room_event!(HistoryVisibilityEvent, RoomHistoryVisibility);
impl_from_t_for_room_event!(JoinRulesEvent, RoomJoinRules);
impl_from_t_for_room_event!(MemberEvent, RoomMember);
impl_from_t_for_room_event!(MessageEvent, RoomMessage);
impl_from_t_for_room_event!(FeedbackEvent, RoomMessageFeedback);
impl_from_t_for_room_event!(NameEvent, RoomName);
impl_from_t_for_room_event!(PinnedEventsEvent, RoomPinnedEvents);
impl_from_t_for_room_event!(PowerLevelsEvent, RoomPowerLevels);
impl_from_t_for_room_event!(RedactionEvent, RoomRedaction);
impl_from_t_for_room_event!(ServerAclEvent, RoomServerAcl);
impl_from_t_for_room_event!(StickerEvent, Sticker);
impl_from_t_for_room_event!(ThirdPartyInviteEvent, RoomThirdPartyInvite);
impl_from_t_for_room_event!(TombstoneEvent, RoomTombstone);
impl_from_t_for_room_event!(TopicEvent, RoomTopic);
impl_from_t_for_room_event!(CustomRoomEvent, CustomRoom);
impl_from_t_for_room_event!(CustomStateEvent, CustomState);
macro_rules! impl_from_t_for_state_event {
($ty:ty, $variant:ident) => {
impl From<$ty> for StateEvent {
fn from(event: $ty) -> Self {
StateEvent::$variant(event)
}
}
};
}
impl_from_t_for_state_event!(AliasesEvent, RoomAliases);
impl_from_t_for_state_event!(AvatarEvent, RoomAvatar);
impl_from_t_for_state_event!(CanonicalAliasEvent, RoomCanonicalAlias);
impl_from_t_for_state_event!(CreateEvent, RoomCreate);
impl_from_t_for_state_event!(EncryptionEvent, RoomEncryption);
impl_from_t_for_state_event!(GuestAccessEvent, RoomGuestAccess);
impl_from_t_for_state_event!(HistoryVisibilityEvent, RoomHistoryVisibility);
impl_from_t_for_state_event!(JoinRulesEvent, RoomJoinRules);
impl_from_t_for_state_event!(MemberEvent, RoomMember);
impl_from_t_for_state_event!(NameEvent, RoomName);
impl_from_t_for_state_event!(PinnedEventsEvent, RoomPinnedEvents);
impl_from_t_for_state_event!(PowerLevelsEvent, RoomPowerLevels);
impl_from_t_for_state_event!(ServerAclEvent, RoomServerAcl);
impl_from_t_for_state_event!(ThirdPartyInviteEvent, RoomThirdPartyInvite);
impl_from_t_for_state_event!(TombstoneEvent, RoomTombstone);
impl_from_t_for_state_event!(TopicEvent, RoomTopic);
impl_from_t_for_state_event!(CustomStateEvent, CustomState);

199
src/collections/raw/only.rs Normal file
View File

@ -0,0 +1,199 @@
//! Enums for heterogeneous collections of events, exclusive to event types that implement "at
//! most" the trait of the same name.
use serde::{Deserialize, Deserializer};
pub use super::all::StateEvent;
use crate::{
call::{
answer::raw::AnswerEvent, candidates::raw::CandidatesEvent, hangup::raw::HangupEvent,
invite::raw::InviteEvent,
},
direct::raw::DirectEvent,
dummy::raw::DummyEvent,
forwarded_room_key::raw::ForwardedRoomKeyEvent,
fully_read::raw::FullyReadEvent,
ignored_user_list::raw::IgnoredUserListEvent,
key::verification::{
accept::raw::AcceptEvent, cancel::raw::CancelEvent, key::raw::KeyEvent, mac::raw::MacEvent,
request::raw::RequestEvent, start::raw::StartEvent,
},
presence::raw::PresenceEvent,
push_rules::raw::PushRulesEvent,
receipt::raw::ReceiptEvent,
room::{
encrypted::raw::EncryptedEvent,
message::{feedback::raw::FeedbackEvent, raw::MessageEvent},
redaction::raw::RedactionEvent,
},
room_key::raw::RoomKeyEvent,
room_key_request::raw::RoomKeyRequestEvent,
sticker::raw::StickerEvent,
tag::raw::TagEvent,
typing::raw::TypingEvent,
CustomEvent, CustomRoomEvent,
};
/// A basic event.
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum Event {
/// m.direct
Direct(DirectEvent),
/// m.dummy
Dummy(DummyEvent),
/// m.forwarded_room_key
ForwardedRoomKey(ForwardedRoomKeyEvent),
/// m.fully_read
FullyRead(FullyReadEvent),
/// m.key.verification.accept
KeyVerificationAccept(AcceptEvent),
/// m.key.verification.cancel
KeyVerificationCancel(CancelEvent),
/// m.key.verification.key
KeyVerificationKey(KeyEvent),
/// m.key.verification.mac
KeyVerificationMac(MacEvent),
/// m.key.verification.request
KeyVerificationRequest(RequestEvent),
/// m.key.verification.start
KeyVerificationStart(StartEvent),
/// m.ignored_user_list
IgnoredUserList(IgnoredUserListEvent),
/// m.presence
Presence(PresenceEvent),
/// m.push_rules
PushRules(PushRulesEvent),
/// m.room_key
RoomKey(RoomKeyEvent),
/// m.room_key_request
RoomKeyRequest(RoomKeyRequestEvent),
/// m.receipt
Receipt(ReceiptEvent),
/// m.tag
Tag(TagEvent),
/// m.typing
Typing(TypingEvent),
/// Any basic event that is not part of the specification.
Custom(CustomEvent),
}
/// A room event.
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum RoomEvent {
/// m.call.answer
CallAnswer(AnswerEvent),
/// m.call.candidates
CallCandidates(CandidatesEvent),
/// m.call.hangup
CallHangup(HangupEvent),
/// m.call.invite
CallInvite(InviteEvent),
/// m.room.encrypted
RoomEncrypted(EncryptedEvent),
/// m.room.message
RoomMessage(MessageEvent),
/// m.room.message.feedback
RoomMessageFeedback(FeedbackEvent),
/// m.room.redaction
RoomRedaction(RedactionEvent),
/// m.sticker
Sticker(StickerEvent),
/// Any room event that is not part of the specification.
CustomRoom(CustomRoomEvent),
}
macro_rules! impl_from_t_for_event {
($ty:ty, $variant:ident) => {
impl From<$ty> for Event {
fn from(event: $ty) -> Self {
Event::$variant(event)
}
}
};
}
impl<'de> Deserialize<'de> for Event {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
unimplemented!()
}
}
impl<'de> Deserialize<'de> for RoomEvent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
unimplemented!()
}
}
impl_from_t_for_event!(DirectEvent, Direct);
impl_from_t_for_event!(DummyEvent, Dummy);
impl_from_t_for_event!(ForwardedRoomKeyEvent, ForwardedRoomKey);
impl_from_t_for_event!(FullyReadEvent, FullyRead);
impl_from_t_for_event!(AcceptEvent, KeyVerificationAccept);
impl_from_t_for_event!(CancelEvent, KeyVerificationCancel);
impl_from_t_for_event!(KeyEvent, KeyVerificationKey);
impl_from_t_for_event!(MacEvent, KeyVerificationMac);
impl_from_t_for_event!(RequestEvent, KeyVerificationRequest);
impl_from_t_for_event!(StartEvent, KeyVerificationStart);
impl_from_t_for_event!(IgnoredUserListEvent, IgnoredUserList);
impl_from_t_for_event!(PresenceEvent, Presence);
impl_from_t_for_event!(PushRulesEvent, PushRules);
impl_from_t_for_event!(ReceiptEvent, Receipt);
impl_from_t_for_event!(TagEvent, Tag);
impl_from_t_for_event!(TypingEvent, Typing);
impl_from_t_for_event!(CustomEvent, Custom);
macro_rules! impl_from_t_for_room_event {
($ty:ty, $variant:ident) => {
impl From<$ty> for RoomEvent {
fn from(event: $ty) -> Self {
RoomEvent::$variant(event)
}
}
};
}
impl_from_t_for_room_event!(AnswerEvent, CallAnswer);
impl_from_t_for_room_event!(CandidatesEvent, CallCandidates);
impl_from_t_for_room_event!(HangupEvent, CallHangup);
impl_from_t_for_room_event!(InviteEvent, CallInvite);
impl_from_t_for_room_event!(EncryptedEvent, RoomEncrypted);
impl_from_t_for_room_event!(MessageEvent, RoomMessage);
impl_from_t_for_room_event!(FeedbackEvent, RoomMessageFeedback);
impl_from_t_for_room_event!(RedactionEvent, RoomRedaction);
impl_from_t_for_room_event!(StickerEvent, Sticker);
impl_from_t_for_room_event!(CustomRoomEvent, CustomRoom);

View File

@ -28,6 +28,7 @@ mod tests {
use serde_json::to_string;
use super::{DirectEvent, DirectEventContent};
use crate::EventResult;
#[test]
fn serialization() {
@ -67,7 +68,10 @@ mod tests {
rooms[1].to_string()
);
let event: DirectEvent = json_data.parse().unwrap();
let event: DirectEvent = serde_json::from_str::<EventResult<_>>(&json_data)
.unwrap()
.into_result()
.unwrap();
let direct_rooms = event.content.get(&alice).unwrap();
assert!(direct_rooms.contains(&rooms[0]));

View File

@ -27,6 +27,7 @@ ruma_event! {
#[cfg(test)]
mod tests {
use super::{DummyEvent, Empty};
use crate::EventResult;
#[test]
fn serialization() {
@ -42,6 +43,9 @@ mod tests {
fn deserialization() {
let json = r#"{"content":{},"type":"m.dummy"}"#;
assert!(json.parse::<DummyEvent>().is_ok());
assert!(serde_json::from_str::<EventResult<DummyEvent>>(json)
.unwrap()
.into_result()
.is_ok());
}
}

View File

@ -1,11 +1,11 @@
//! Types for the *m.ignored_user_list* event.
use std::collections::HashMap;
use std::convert::TryFrom;
use ruma_identifiers::UserId;
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use crate::{Empty, Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent};
use crate::{vec_as_map_of_empty, Event as _, EventType, Void};
/// A list of users to ignore.
#[derive(Clone, Debug, PartialEq)]
@ -15,36 +15,29 @@ pub struct IgnoredUserListEvent {
}
/// The payload for `IgnoredUserListEvent`.
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq, Serialize)]
pub struct IgnoredUserListEventContent {
/// A list of users to ignore.
pub ignored_users: Vec<UserId>,
}
impl<'de> Deserialize<'de> for EventResult<IgnoredUserListEvent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
impl TryFrom<raw::IgnoredUserListEvent> for IgnoredUserListEvent {
type Error = (raw::IgnoredUserListEvent, Void);
let raw: raw::IgnoredUserListEvent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
fn try_from(raw: raw::IgnoredUserListEvent) -> Result<Self, Self::Error> {
Ok(Self {
content: crate::convert_content(raw.content),
})
}
}
Ok(EventResult::Ok(IgnoredUserListEvent {
content: IgnoredUserListEventContent {
ignored_users: raw.content.ignored_users.keys().cloned().collect(),
},
}))
impl TryFrom<raw::IgnoredUserListEventContent> for IgnoredUserListEventContent {
type Error = (raw::IgnoredUserListEventContent, Void);
fn try_from(raw: raw::IgnoredUserListEventContent) -> Result<Self, Self::Error> {
Ok(Self {
ignored_users: raw.ignored_users,
})
}
}
@ -65,54 +58,12 @@ impl Serialize for IgnoredUserListEvent {
impl_event!(
IgnoredUserListEvent,
IgnoredUserListEventContent,
EventType::IgnoredUserList
EventType::IgnoredUserList,
raw
);
impl<'de> Deserialize<'de> for EventResult<IgnoredUserListEventContent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
let raw: raw::IgnoredUserListEventContent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(IgnoredUserListEventContent {
ignored_users: raw.ignored_users.keys().cloned().collect(),
}))
}
}
impl Serialize for IgnoredUserListEventContent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = HashMap::new();
for user_id in &self.ignored_users {
map.insert(user_id.clone(), Empty);
}
let raw = raw::IgnoredUserListEventContent { ignored_users: map };
raw.serialize(serializer)
}
}
mod raw {
pub(crate) mod raw {
use super::*;
use crate::Empty;
/// A list of users to ignore.
#[derive(Clone, Debug, Deserialize)]
@ -125,7 +76,8 @@ mod raw {
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IgnoredUserListEventContent {
/// A list of users to ignore.
pub ignored_users: HashMap<UserId, Empty>,
#[serde(with = "vec_as_map_of_empty")]
pub ignored_users: Vec<UserId>,
}
}
@ -135,7 +87,8 @@ mod tests {
use ruma_identifiers::UserId;
use super::{EventResult, IgnoredUserListEvent, IgnoredUserListEventContent};
use super::{IgnoredUserListEvent, IgnoredUserListEventContent};
use crate::EventResult;
#[test]
fn serialization() {

View File

@ -1,5 +1,7 @@
//! Types for the *m.key.verification.start* event.
use std::convert::{TryFrom, TryInto as _};
use ruma_identifiers::DeviceId;
use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::{from_value, Value};
@ -8,7 +10,7 @@ use super::{
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, ShortAuthenticationString,
VerificationMethod,
};
use crate::{Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent, InvalidInput};
use crate::{Event, EventType, InvalidInput};
/// Begins an SAS key verification process.
///
@ -31,38 +33,14 @@ pub enum StartEventContent {
__Nonexhaustive,
}
impl<'de> Deserialize<'de> for EventResult<StartEvent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
impl TryFrom<raw::StartEvent> for StartEvent {
type Error = (raw::StartEvent, &'static str);
let raw: raw::StartEvent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
let content = match StartEventContent::from_raw(raw.content) {
Ok(content) => content,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(StartEvent { content }))
fn try_from(raw: raw::StartEvent) -> Result<Self, Self::Error> {
match raw.content.try_into() {
Ok(content) => Ok(Self { content }),
Err((content, msg)) => Err((raw::StartEvent { content }, msg)),
}
}
}
@ -83,78 +61,62 @@ impl Serialize for StartEvent {
impl_event!(
StartEvent,
StartEventContent,
EventType::KeyVerificationStart
EventType::KeyVerificationStart,
raw
);
impl StartEventContent {
fn from_raw(raw: raw::StartEventContent) -> Result<Self, &'static str> {
impl TryFrom<raw::StartEventContent> for StartEventContent {
type Error = (raw::StartEventContent, &'static str);
fn try_from(raw: raw::StartEventContent) -> Result<Self, Self::Error> {
match raw {
raw::StartEventContent::MSasV1(content) => {
if !content
.key_agreement_protocols
.contains(&KeyAgreementProtocol::Curve25519)
{
return Err("`key_agreement_protocols` must contain at least `KeyAgreementProtocol::Curve25519`");
return Err(
(raw::StartEventContent::MSasV1(content),
"`key_agreement_protocols` must contain at least `KeyAgreementProtocol::Curve25519`",
));
}
if !content.hashes.contains(&HashAlgorithm::Sha256) {
return Err("`hashes` must contain at least `HashAlgorithm::Sha256`");
return Err((
raw::StartEventContent::MSasV1(content),
"`hashes` must contain at least `HashAlgorithm::Sha256`",
));
}
if !content
.message_authentication_codes
.contains(&MessageAuthenticationCode::HkdfHmacSha256)
{
return Err("`message_authentication_codes` must contain at least `MessageAuthenticationCode::HkdfHmacSha256`");
return Err(
(raw::StartEventContent::MSasV1(content),
"`message_authentication_codes` must contain at least `MessageAuthenticationCode::HkdfHmacSha256`",
));
}
if !content
.short_authentication_string
.contains(&ShortAuthenticationString::Decimal)
{
return Err("`short_authentication_string` must contain at least `ShortAuthenticationString::Decimal`");
return Err(
(raw::StartEventContent::MSasV1(content),
"`short_authentication_string` must contain at least `ShortAuthenticationString::Decimal`",
));
}
Ok(StartEventContent::MSasV1(content))
}
raw::StartEventContent::__Nonexhaustive => {
panic!("__Nonexhaustive enum variant is not intended for use.");
panic!("__Nonexhaustive enum variant is not intended for use.".to_owned());
}
}
}
}
impl<'de> Deserialize<'de> for EventResult<StartEventContent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
let raw: raw::StartEventContent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
match StartEventContent::from_raw(raw) {
Ok(content) => Ok(EventResult::Ok(content)),
Err(error) => Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
))),
}
}
}
impl Serialize for StartEventContent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@ -167,7 +129,7 @@ impl Serialize for StartEventContent {
}
}
mod raw {
pub(crate) mod raw {
use super::*;
/// Begins an SAS key verification process.
@ -374,9 +336,10 @@ mod tests {
use serde_json::to_string;
use super::{
EventResult, HashAlgorithm, KeyAgreementProtocol, MSasV1Content, MSasV1ContentOptions,
HashAlgorithm, KeyAgreementProtocol, MSasV1Content, MSasV1ContentOptions,
MessageAuthenticationCode, ShortAuthenticationString, StartEvent, StartEventContent,
};
use crate::EventResult;
#[test]
fn invalid_m_sas_v1_content_missing_required_key_agreement_protocols() {
@ -536,7 +499,7 @@ mod tests {
.unwrap_err();
assert!(error.message().contains("key_agreement_protocols"));
assert!(error.json().is_some());
assert!(error.raw_data().is_some());
}
#[test]
@ -550,7 +513,7 @@ mod tests {
.unwrap_err();
assert!(error.message().contains("hashes"));
assert!(error.json().is_some());
assert!(error.raw_data().is_some());
}
#[test]
@ -564,7 +527,7 @@ mod tests {
.unwrap_err();
assert!(error.message().contains("message_authentication_codes"));
assert!(error.json().is_some());
assert!(error.raw_data().is_some());
}
#[test]
@ -578,7 +541,7 @@ mod tests {
.unwrap_err();
assert!(error.message().contains("short_authentication_string"));
assert!(error.json().is_some());
assert!(error.raw_data().is_some());
}
#[test]
@ -593,6 +556,6 @@ mod tests {
.unwrap_err();
assert!(error.message().contains("key_agreement_protocols"));
assert!(error.json().is_some());
assert!(error.raw_data().is_some());
}
}

View File

@ -112,37 +112,41 @@
#![deny(missing_debug_implementations)]
#![deny(missing_docs)]
#![deny(warnings)]
//#![deny(warnings)]
use std::{
collections::HashMap,
convert::TryInto,
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter, Result as FmtResult},
hash::Hash,
};
use js_int::UInt;
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{
de::{Error as SerdeError, IntoDeserializer, MapAccess, Visitor},
de::{DeserializeOwned, Error as SerdeError, IntoDeserializer, MapAccess, Visitor},
ser::SerializeMap,
Deserialize, Deserializer, Serialize, Serializer,
};
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;
mod raw {
pub mod all;
pub mod only;
}
}
pub mod direct;
pub mod dummy;
pub mod forwarded_room_key;
@ -168,60 +172,65 @@ pub mod typing;
/// 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(InnerInvalidEvent);
#[derive(Clone, Debug)]
pub struct InvalidEvent<T>(InnerInvalidEvent<T>);
impl InvalidEvent {
impl<T> InvalidEvent<T> {
/// A message describing why the event is invalid.
pub fn message(&self) -> String {
match self.0 {
InnerInvalidEvent::Deserialization { ref error } => error.to_string(),
InnerInvalidEvent::Deserialization { ref error, .. } => error.to_string(),
InnerInvalidEvent::Validation { ref message, .. } => message.to_string(),
}
}
/// The raw `serde_json::Value` representation of the invalid event, if available.
/// The raw event data, if deserialization succeeded but validation failed.
pub fn raw_data(&self) -> Option<&T> {
match self.0 {
InnerInvalidEvent::Validation { ref raw_data, .. } => Some(raw_data),
_ => None,
}
}
/// The `serde_json::Value` representation of the invalid event, if deserialization failed.
pub fn json(&self) -> Option<&Value> {
match self.0 {
InnerInvalidEvent::Validation { ref json, .. } => Some(json),
InnerInvalidEvent::Deserialization { ref json, .. } => Some(json),
_ => None,
}
}
}
impl Display for InvalidEvent {
impl<T> Display for InvalidEvent<T> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{}", self.message())
}
}
impl Error for InvalidEvent {}
impl<T: Debug> Error for InvalidEvent<T> {}
/// An event that is malformed or otherwise invalid.
#[derive(Debug)]
enum InnerInvalidEvent {
#[derive(Clone, Debug)]
enum InnerInvalidEvent<T> {
/// An event that failed to deserialize from JSON.
Deserialization {
/// The raw `serde_json::Value` representation of the invalid event.
json: Value,
/// The deserialization error returned by serde.
error: serde_json::Error,
error: String,
},
/// An event that deserialized but failed validation.
Validation {
/// The raw `serde_json::Value` representation of the invalid event.
json: Value,
/// The event data that failed validation.
raw_data: T,
/// An message describing why the event was invalid.
message: String,
},
}
impl From<serde_json::Error> for InvalidEvent {
fn from(error: serde_json::Error) -> Self {
InvalidEvent(InnerInvalidEvent::Deserialization { error })
}
}
/// An error returned when attempting to create an event with data that would make it invalid.
///
/// This type is similar to `InvalidEvent`, but used during the construction of a new event, as
@ -237,47 +246,64 @@ impl Display for InvalidInput {
impl Error for InvalidInput {}
/// Marks types that can be deserialized as EventResult<Self>
pub trait EventResultCompatible: Sized {
/// The raw form of this event that deserialization falls back to if deserializing `Self` fails.
type Raw: DeserializeOwned + TryInto<Self>;
}
/// An empty type
#[derive(Debug)]
pub enum Void {}
impl From<Void> for String {
fn from(v: Void) -> Self {
match v {}
}
}
fn convert_content<T, Raw>(res: Raw) -> T
where
Raw: TryInto<T, Error = (Raw, Void)>,
{
match res.try_into() {
Ok(c) => c,
Err((_, void)) => match void {},
}
}
/// The result of deserializing an event, which may or may not be valid.
///
/// When data is successfully deserialized and validated, this structure will contain the
/// deserialized value `T`. When deserialization succeeds, but the event is invalid for any reason,
/// this structure will contain an `InvalidEvent`. See the documentation for `InvalidEvent` for
/// more details.
#[derive(Debug)]
pub enum EventResult<T> {
#[derive(Clone, Debug)]
pub enum EventResult<T: EventResultCompatible> {
/// `T` deserialized and validated successfully.
Ok(T),
/// `T` deserialized but was invalid.
/// `T` failed either deserialization or validation.
///
/// `InvalidEvent` contains the original input.
Err(InvalidEvent),
/// `InvalidEvent` contains the error message and the raw data.
Err(InvalidEvent<T::Raw>),
}
impl<T> EventResult<T> {
impl<T: EventResultCompatible> EventResult<T> {
/// Convert `EventResult<T>` into the equivalent `std::result::Result<T, InvalidEvent>`.
pub fn into_result(self) -> Result<T, InvalidEvent> {
pub fn into_result(self) -> Result<T, InvalidEvent<T::Raw>> {
match self {
EventResult::Ok(t) => Ok(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>>
impl<'de, T, E> Deserialize<'de> for EventResult<T>
where
K: for<'inner> Deserialize<'inner> + Eq + Hash,
V: for<'inner> Deserialize<'inner>,
T: EventResultCompatible,
T::Raw: TryInto<T, Error = (T::Raw, E)>,
E: Into<String>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
@ -285,19 +311,36 @@ where
{
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,
let raw_data: T::Raw = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
InnerInvalidEvent::Deserialization {
json,
message: error.to_string(),
error: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(hash_map))
match raw_data.try_into() {
Ok(value) => Ok(EventResult::Ok(value)),
Err((raw_data, msg)) => Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
message: msg.into(),
raw_data,
},
))),
}
}
}
impl<T: EventResultCompatible> Serialize for EventResult<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
unimplemented!()
}
}
@ -358,29 +401,6 @@ 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 {
@ -523,12 +543,7 @@ pub enum EventType {
}
/// A basic event.
pub trait Event
where
Self: Debug + Serialize + Sized,
for<'de> EventResult<Self>: Deserialize<'de>,
for<'de> EventResult<Self::Content>: Deserialize<'de>,
{
pub trait Event: Debug + Serialize + Sized + EventResultCompatible {
/// The type of this event's `content` field.
type Content: Debug + Serialize;
@ -540,11 +555,7 @@ where
}
/// An event within the context of a room.
pub trait RoomEvent: Event
where
for<'de> EventResult<Self>: Deserialize<'de>,
for<'de> EventResult<<Self as Event>::Content>: Deserialize<'de>,
{
pub trait RoomEvent: Event {
/// The unique identifier for the event.
fn event_id(&self) -> &EventId;
@ -566,11 +577,7 @@ where
}
/// An event that describes persistent state about a room.
pub trait StateEvent: RoomEvent
where
for<'de> EventResult<Self>: Deserialize<'de>,
for<'de> EventResult<<Self as Event>::Content>: Deserialize<'de>,
{
pub trait StateEvent: RoomEvent {
/// The previous content for this state key, if any.
fn prev_content(&self) -> Option<&Self::Content>;
@ -578,56 +585,56 @@ where
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> {
@ -874,6 +881,35 @@ where
}
}
/// Serde serialization and deserialization functions that map a `Vec` to a
///
/// To be used as `#[serde(with = "vec_as_map_of_empty")]
mod vec_as_map_of_empty {
use super::Empty;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{collections::HashMap, hash::Hash};
pub fn serialize<S, T>(vec: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: Serialize + Hash + Eq,
{
vec.into_iter()
.map(|v| (v, Empty))
.collect::<HashMap<_, _>>()
.serialize(serializer)
}
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
T: Deserialize<'de> + Hash + Eq,
{
HashMap::<T, Empty>::deserialize(deserializer)
.map(|hashmap| hashmap.into_iter().map(|(k, _)| k).collect())
}
}
/// Used to default the `bool` fields to `true` during deserialization.
fn default_true() -> bool {
true

View File

@ -25,8 +25,16 @@ macro_rules! impl_enum {
}
macro_rules! impl_event {
($name:ident, $content_name:ident, $event_type:path) => {
impl Event for $name {
($name:ident, $content_name:ident, $event_type:path, $raw_mod:ident) => {
impl crate::EventResultCompatible for $name {
type Raw = $raw_mod::$name;
}
impl crate::EventResultCompatible for $content_name {
type Raw = $raw_mod::$content_name;
}
impl crate::Event for $name {
/// The type of this event's `content` field.
type Content = $content_name;
@ -36,7 +44,7 @@ macro_rules! impl_event {
}
/// The type of the event.
fn event_type(&self) -> EventType {
fn event_type(&self) -> crate::EventType {
$event_type
}
}
@ -44,8 +52,8 @@ macro_rules! impl_event {
}
macro_rules! impl_room_event {
($name:ident, $content_name:ident, $event_type:path) => {
impl_event!($name, $content_name, $event_type);
($name:ident, $content_name:ident, $event_type:path, $raw_mod:ident) => {
impl_event!($name, $content_name, $event_type, $raw_mod);
impl RoomEvent for $name {
/// The unique identifier for the event.
@ -81,8 +89,8 @@ macro_rules! impl_room_event {
}
macro_rules! impl_state_event {
($name:ident, $content_name:ident, $event_type:path) => {
impl_room_event!($name, $content_name, $event_type);
($name:ident, $content_name:ident, $event_type:path, $raw_mod:ident) => {
impl_room_event!($name, $content_name, $event_type, $raw_mod);
impl StateEvent for $name {
/// The previous content for this state key, if any.

View File

@ -80,6 +80,7 @@ mod tests {
use serde_json::to_string;
use super::{PresenceEvent, PresenceEventContent, PresenceState};
use crate::EventResult;
#[test]
fn serialization() {
@ -118,6 +119,12 @@ mod tests {
let json =
r#"{"content":{"avatar_url":"mxc://localhost:wefuiwegh8742w","currently_active":false,"last_active_ago":2478593,"presence":"online","status_msg":"Making cupcakes"},"sender":"@example:localhost","type":"m.presence"}"#;
assert_eq!(json.parse::<PresenceEvent>().unwrap(), event);
assert_eq!(
serde_json::from_str::<EventResult<PresenceEvent>>(json)
.unwrap()
.into_result()
.unwrap(),
event
);
}
}

View File

@ -439,6 +439,7 @@ mod tests {
Action, EventMatchCondition, PushCondition, PushRulesEvent, RoomMemberCountCondition,
SenderNotificationPermissionCondition, Tweak,
};
use crate::EventResult;
#[test]
fn serialize_string_action() {
@ -776,6 +777,9 @@ mod tests {
},
"type": "m.push_rules"
}"#;
assert!(json.parse::<PushRulesEvent>().is_ok());
assert!(serde_json::from_str::<EventResult<PushRulesEvent>>(json)
.unwrap()
.into_result()
.is_ok());
}
}

View File

@ -1,14 +1,13 @@
//! Types for the *m.room.canonical_alias* event.
use std::convert::TryFrom;
use js_int::UInt;
use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use serde_json::Value;
use crate::{
empty_string_as_none, Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent,
RoomEvent, StateEvent,
};
use crate::{empty_string_as_none, Event, EventType, RoomEvent, StateEvent, Void};
/// Informs the room as to which alias is the canonical one.
#[derive(Clone, Debug, PartialEq)]
@ -48,39 +47,28 @@ pub struct CanonicalAliasEventContent {
pub alias: Option<RoomAliasId>,
}
impl<'de> Deserialize<'de> for EventResult<CanonicalAliasEvent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
impl TryFrom<raw::CanonicalAliasEvent> for CanonicalAliasEvent {
type Error = (raw::CanonicalAliasEvent, Void);
let raw: raw::CanonicalAliasEvent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(CanonicalAliasEvent {
content: CanonicalAliasEventContent {
alias: raw.content.alias,
},
fn try_from(raw: raw::CanonicalAliasEvent) -> Result<Self, Self::Error> {
Ok(Self {
content: crate::convert_content(raw.content),
event_id: raw.event_id,
origin_server_ts: raw.origin_server_ts,
prev_content: raw
.prev_content
.map(|prev| CanonicalAliasEventContent { alias: prev.alias }),
prev_content: raw.prev_content.map(crate::convert_content),
room_id: raw.room_id,
sender: raw.sender,
state_key: raw.state_key,
unsigned: raw.unsigned,
}))
})
}
}
impl TryFrom<raw::CanonicalAliasEventContent> for CanonicalAliasEventContent {
type Error = (raw::CanonicalAliasEventContent, Void);
fn try_from(raw: raw::CanonicalAliasEventContent) -> Result<Self, Self::Error> {
Ok(Self { alias: raw.alias })
}
}
@ -132,35 +120,11 @@ impl Serialize for CanonicalAliasEvent {
impl_state_event!(
CanonicalAliasEvent,
CanonicalAliasEventContent,
EventType::RoomCanonicalAlias
EventType::RoomCanonicalAlias,
raw
);
impl<'de> Deserialize<'de> for EventResult<CanonicalAliasEventContent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
let raw: raw::CanonicalAliasEventContent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(CanonicalAliasEventContent {
alias: raw.alias,
}))
}
}
mod raw {
pub(crate) mod raw {
use super::*;
/// Informs the room as to which alias is the canonical one.
@ -213,7 +177,8 @@ mod tests {
use js_int::UInt;
use ruma_identifiers::{EventId, RoomAliasId, UserId};
use super::{CanonicalAliasEvent, CanonicalAliasEventContent, EventResult};
use super::{CanonicalAliasEvent, CanonicalAliasEventContent};
use crate::EventResult;
#[test]
fn serialization_with_optional_fields_as_none() {

View File

@ -56,6 +56,7 @@ mod tests {
use ruma_identifiers::{RoomVersionId, UserId};
use super::CreateEventContent;
use crate::EventResult;
#[test]
fn serialization() {
@ -82,6 +83,12 @@ mod tests {
let json = r#"{"creator":"@carl:example.com","m.federate":true,"room_version":"4"}"#;
assert_eq!(json.parse::<CreateEventContent>().unwrap(), content);
assert_eq!(
serde_json::from_str::<EventResult<CreateEventContent>>(json)
.unwrap()
.into_result()
.unwrap(),
content
);
}
}

View File

@ -1,11 +1,13 @@
//! Types for the *m.room.encrypted* event.
use std::convert::TryFrom;
use js_int::UInt;
use ruma_identifiers::{DeviceId, EventId, RoomId, UserId};
use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::{from_value, Value};
use crate::{Algorithm, Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent, RoomEvent};
use crate::{Algorithm, Event, EventType, RoomEvent, Void};
/// This event type is used when sending encrypted events.
///
@ -48,45 +50,34 @@ pub enum EncryptedEventContent {
__Nonexhaustive,
}
impl<'de> Deserialize<'de> for EventResult<EncryptedEvent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
impl TryFrom<raw::EncryptedEvent> for EncryptedEvent {
type Error = (raw::EncryptedEvent, Void);
let raw: raw::EncryptedEvent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
let content = match raw.content {
raw::EncryptedEventContent::OlmV1Curve25519AesSha2(content) => {
EncryptedEventContent::OlmV1Curve25519AesSha2(content)
}
raw::EncryptedEventContent::MegolmV1AesSha2(content) => {
EncryptedEventContent::MegolmV1AesSha2(content)
}
raw::EncryptedEventContent::__Nonexhaustive => {
panic!("__Nonexhaustive enum variant is not intended for use.");
}
};
Ok(EventResult::Ok(EncryptedEvent {
content,
fn try_from(raw: raw::EncryptedEvent) -> Result<Self, Self::Error> {
Ok(Self {
content: crate::convert_content(raw.content),
event_id: raw.event_id,
origin_server_ts: raw.origin_server_ts,
room_id: raw.room_id,
sender: raw.sender,
unsigned: raw.unsigned,
}))
})
}
}
impl TryFrom<raw::EncryptedEventContent> for EncryptedEventContent {
type Error = (raw::EncryptedEventContent, Void);
fn try_from(raw: raw::EncryptedEventContent) -> Result<Self, Self::Error> {
use raw::EncryptedEventContent::*;
Ok(match raw {
OlmV1Curve25519AesSha2(content) => Self::OlmV1Curve25519AesSha2(content),
MegolmV1AesSha2(content) => Self::MegolmV1AesSha2(content),
__Nonexhaustive => {
unreachable!("__Nonexhaustive variant should be impossible to obtain.")
}
})
}
}
@ -129,42 +120,10 @@ impl Serialize for EncryptedEvent {
impl_room_event!(
EncryptedEvent,
EncryptedEventContent,
EventType::RoomEncrypted
EventType::RoomEncrypted,
raw
);
impl<'de> Deserialize<'de> for EventResult<EncryptedEventContent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
let raw: raw::EncryptedEventContent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
match raw {
raw::EncryptedEventContent::OlmV1Curve25519AesSha2(content) => Ok(EventResult::Ok(
EncryptedEventContent::OlmV1Curve25519AesSha2(content),
)),
raw::EncryptedEventContent::MegolmV1AesSha2(content) => Ok(EventResult::Ok(
EncryptedEventContent::MegolmV1AesSha2(content),
)),
raw::EncryptedEventContent::__Nonexhaustive => {
panic!("__Nonexhaustive enum variant is not intended for use.");
}
}
}
}
impl Serialize for EncryptedEventContent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@ -180,7 +139,7 @@ impl Serialize for EncryptedEventContent {
}
}
mod raw {
pub(crate) mod raw {
use super::*;
/// This event type is used when sending encrypted events.
@ -318,7 +277,8 @@ pub struct MegolmV1AesSha2Content {
mod tests {
use serde_json::to_string;
use super::{Algorithm, EncryptedEventContent, EventResult, MegolmV1AesSha2Content};
use super::{Algorithm, EncryptedEventContent, MegolmV1AesSha2Content};
use crate::EventResult;
#[test]
fn serializtion() {

View File

@ -1,5 +1,7 @@
//! Types for the *m.room.message* event.
use std::convert::TryFrom;
use js_int::UInt;
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{
@ -10,7 +12,7 @@ use serde::{
use serde_json::{from_value, Value};
use super::{EncryptedFile, ImageInfo, ThumbnailInfo};
use crate::{Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent, RoomEvent};
use crate::{Event, EventType, RoomEvent, Void};
pub mod feedback;
@ -74,50 +76,41 @@ pub enum MessageEventContent {
__Nonexhaustive,
}
impl<'de> Deserialize<'de> for EventResult<MessageEvent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
impl TryFrom<raw::MessageEvent> for MessageEvent {
type Error = (raw::MessageEvent, Void);
let raw: raw::MessageEvent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(MessageEvent {
content: match raw.content {
raw::MessageEventContent::Audio(content) => MessageEventContent::Audio(content),
raw::MessageEventContent::Emote(content) => MessageEventContent::Emote(content),
raw::MessageEventContent::File(content) => MessageEventContent::File(content),
raw::MessageEventContent::Image(content) => MessageEventContent::Image(content),
raw::MessageEventContent::Location(content) => {
MessageEventContent::Location(content)
}
raw::MessageEventContent::Notice(content) => MessageEventContent::Notice(content),
raw::MessageEventContent::ServerNotice(content) => {
MessageEventContent::ServerNotice(content)
}
raw::MessageEventContent::Text(content) => MessageEventContent::Text(content),
raw::MessageEventContent::Video(content) => MessageEventContent::Video(content),
raw::MessageEventContent::__Nonexhaustive => {
panic!("__Nonexhaustive enum variant is not intended for use.")
}
},
fn try_from(raw: raw::MessageEvent) -> Result<Self, Self::Error> {
Ok(Self {
content: crate::convert_content(raw.content),
event_id: raw.event_id,
origin_server_ts: raw.origin_server_ts,
room_id: raw.room_id,
sender: raw.sender,
unsigned: raw.unsigned,
}))
})
}
}
impl TryFrom<raw::MessageEventContent> for MessageEventContent {
type Error = (raw::MessageEventContent, Void);
fn try_from(raw: raw::MessageEventContent) -> Result<Self, Self::Error> {
use raw::MessageEventContent::*;
Ok(match raw {
Audio(content) => Self::Audio(content),
Emote(content) => Self::Emote(content),
File(content) => Self::File(content),
Image(content) => Self::Image(content),
Location(content) => Self::Location(content),
Notice(content) => Self::Notice(content),
ServerNotice(content) => Self::ServerNotice(content),
Text(content) => Self::Text(content),
Video(content) => Self::Video(content),
__Nonexhaustive => {
unreachable!("It should be impossible to obtain a __Nonexhaustive variant.")
}
})
}
}
@ -157,7 +150,12 @@ impl Serialize for MessageEvent {
}
}
impl_room_event!(MessageEvent, MessageEventContent, EventType::RoomMessage);
impl_room_event!(
MessageEvent,
MessageEventContent,
EventType::RoomMessage,
raw
);
impl Serialize for MessageEventContent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@ -181,47 +179,7 @@ impl Serialize for MessageEventContent {
}
}
impl<'de> Deserialize<'de> for EventResult<MessageEventContent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
let raw: raw::MessageEventContent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
let content = match raw {
raw::MessageEventContent::Audio(content) => MessageEventContent::Audio(content),
raw::MessageEventContent::Emote(content) => MessageEventContent::Emote(content),
raw::MessageEventContent::File(content) => MessageEventContent::File(content),
raw::MessageEventContent::Image(content) => MessageEventContent::Image(content),
raw::MessageEventContent::Location(content) => MessageEventContent::Location(content),
raw::MessageEventContent::Notice(content) => MessageEventContent::Notice(content),
raw::MessageEventContent::ServerNotice(content) => {
MessageEventContent::ServerNotice(content)
}
raw::MessageEventContent::Text(content) => MessageEventContent::Text(content),
raw::MessageEventContent::Video(content) => MessageEventContent::Video(content),
raw::MessageEventContent::__Nonexhaustive => {
panic!("__Nonexhaustive enum variant is not intended for use.")
}
};
Ok(EventResult::Ok(content))
}
}
mod raw {
pub(crate) mod raw {
use super::*;
/// A message sent to a room.
@ -1085,7 +1043,8 @@ impl Serialize for VideoMessageEventContent {
mod tests {
use serde_json::to_string;
use super::{AudioMessageEventContent, EventResult, MessageEventContent};
use super::{AudioMessageEventContent, MessageEventContent};
use crate::EventResult;
#[test]
fn serialization() {

View File

@ -1,13 +1,14 @@
//! Types for the *m.room.name* event.
use std::convert::TryFrom;
use js_int::UInt;
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use serde_json::Value;
use crate::{
empty_string_as_none, Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent,
InvalidInput, RoomEvent, StateEvent,
empty_string_as_none, Event as _, EventType, InvalidInput, RoomEvent, StateEvent, Void,
};
/// A human-friendly room name designed to be displayed to the end-user.
@ -46,39 +47,28 @@ pub struct NameEventContent {
pub(crate) name: Option<String>,
}
impl<'de> Deserialize<'de> for EventResult<NameEvent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
impl TryFrom<raw::NameEvent> for NameEvent {
type Error = (raw::NameEvent, Void);
let raw: raw::NameEvent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(NameEvent {
content: NameEventContent {
name: raw.content.name,
},
fn try_from(raw: raw::NameEvent) -> Result<Self, Self::Error> {
Ok(Self {
content: crate::convert_content(raw.content),
event_id: raw.event_id,
origin_server_ts: raw.origin_server_ts,
prev_content: raw
.prev_content
.map(|prev| NameEventContent { name: prev.name }),
prev_content: raw.prev_content.map(crate::convert_content),
room_id: raw.room_id,
sender: raw.sender,
state_key: raw.state_key,
unsigned: raw.unsigned,
}))
})
}
}
impl TryFrom<raw::NameEventContent> for NameEventContent {
type Error = (raw::NameEventContent, Void);
fn try_from(raw: raw::NameEventContent) -> Result<Self, Self::Error> {
Ok(Self { name: raw.name })
}
}
@ -127,7 +117,7 @@ impl Serialize for NameEvent {
}
}
impl_state_event!(NameEvent, NameEventContent, EventType::RoomName);
impl_state_event!(NameEvent, NameEventContent, EventType::RoomName, raw);
impl NameEventContent {
/// Create a new `NameEventContent` with the given name.
@ -151,30 +141,7 @@ impl NameEventContent {
}
}
impl<'de> Deserialize<'de> for EventResult<NameEventContent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
let raw: raw::NameEventContent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(NameEventContent { name: raw.name }))
}
}
mod raw {
pub(crate) mod raw {
use super::*;
/// A human-friendly room name designed to be displayed to the end-user.
@ -226,7 +193,8 @@ mod tests {
use ruma_identifiers::{EventId, RoomId, UserId};
use serde_json::Value;
use super::{EventResult, NameEvent, NameEventContent};
use super::{NameEvent, NameEventContent};
use crate::EventResult;
#[test]
fn serialization_with_optional_fields_as_none() {

View File

@ -25,7 +25,7 @@ mod tests {
use crate::{
room::pinned_events::{PinnedEventsEvent, PinnedEventsEventContent},
Event, RoomEvent, StateEvent,
Event, EventResult, RoomEvent, StateEvent,
};
#[test]
@ -47,7 +47,11 @@ mod tests {
};
let serialized_event = to_string(&event).unwrap();
let parsed_event: PinnedEventsEvent = serialized_event.parse().unwrap();
let parsed_event: PinnedEventsEvent =
serde_json::from_str::<EventResult<_>>(&serialized_event)
.unwrap()
.into_result()
.unwrap();
assert_eq!(parsed_event.event_id(), event.event_id());
assert_eq!(parsed_event.room_id(), event.room_id());

View File

@ -1,15 +1,13 @@
//! Types for the *m.room.power_levels* event.
use std::collections::HashMap;
use std::{collections::HashMap, convert::TryFrom};
use js_int::{Int, UInt};
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use serde_json::Value;
use crate::{
Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent, RoomEvent, StateEvent,
};
use crate::{Event, EventType, RoomEvent, StateEvent, Void};
/// Defines the power levels (privileges) of users in the room.
#[derive(Clone, Debug, PartialEq)]
@ -87,57 +85,39 @@ pub struct PowerLevelsEventContent {
pub notifications: NotificationPowerLevels,
}
impl<'de> Deserialize<'de> for EventResult<PowerLevelsEvent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
impl TryFrom<raw::PowerLevelsEvent> for PowerLevelsEvent {
type Error = (raw::PowerLevelsEvent, Void);
let raw: raw::PowerLevelsEvent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(PowerLevelsEvent {
content: PowerLevelsEventContent {
ban: raw.content.ban,
events: raw.content.events,
events_default: raw.content.events_default,
invite: raw.content.invite,
kick: raw.content.kick,
redact: raw.content.redact,
state_default: raw.content.state_default,
users: raw.content.users,
users_default: raw.content.users_default,
notifications: raw.content.notifications,
},
fn try_from(raw: raw::PowerLevelsEvent) -> Result<Self, Self::Error> {
Ok(Self {
content: crate::convert_content(raw.content),
event_id: raw.event_id,
origin_server_ts: raw.origin_server_ts,
prev_content: raw.prev_content.map(|prev| PowerLevelsEventContent {
ban: prev.ban,
events: prev.events,
events_default: prev.events_default,
invite: prev.invite,
kick: prev.kick,
redact: prev.redact,
state_default: prev.state_default,
users: prev.users,
users_default: prev.users_default,
notifications: prev.notifications,
}),
prev_content: raw.prev_content.map(crate::convert_content),
room_id: raw.room_id,
unsigned: raw.unsigned,
sender: raw.sender,
state_key: raw.state_key,
unsigned: raw.unsigned,
}))
})
}
}
impl TryFrom<raw::PowerLevelsEventContent> for PowerLevelsEventContent {
type Error = (raw::PowerLevelsEventContent, Void);
fn try_from(raw: raw::PowerLevelsEventContent) -> Result<Self, Self::Error> {
Ok(Self {
ban: raw.ban,
events: raw.events,
events_default: raw.events_default,
invite: raw.invite,
kick: raw.kick,
redact: raw.redact,
state_default: raw.state_default,
users: raw.users,
users_default: raw.users_default,
notifications: raw.notifications,
})
}
}
@ -189,44 +169,11 @@ impl Serialize for PowerLevelsEvent {
impl_state_event!(
PowerLevelsEvent,
PowerLevelsEventContent,
EventType::RoomPowerLevels
EventType::RoomPowerLevels,
raw
);
impl<'de> Deserialize<'de> for EventResult<PowerLevelsEventContent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
let raw: raw::PowerLevelsEventContent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(PowerLevelsEventContent {
ban: raw.ban,
events: raw.events,
events_default: raw.events_default,
invite: raw.invite,
kick: raw.kick,
redact: raw.redact,
state_default: raw.state_default,
users: raw.users,
users_default: raw.users_default,
notifications: raw.notifications,
}))
}
}
mod raw {
pub(crate) mod raw {
use super::*;
/// Defines the power levels (privileges) of users in the room.

View File

@ -1,14 +1,13 @@
//! Types for the *m.room.server_acl* event.
use std::convert::TryFrom;
use js_int::UInt;
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use serde_json::Value;
use crate::{
default_true, Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent, RoomEvent,
StateEvent,
};
use crate::{default_true, Event as _, EventType, RoomEvent, StateEvent, Void};
/// An event to indicate which servers are permitted to participate in the room.
#[derive(Clone, Debug, PartialEq)]
@ -68,43 +67,32 @@ pub struct ServerAclEventContent {
pub deny: Vec<String>,
}
impl<'de> Deserialize<'de> for EventResult<ServerAclEvent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
impl TryFrom<raw::ServerAclEvent> for ServerAclEvent {
type Error = (raw::ServerAclEvent, Void);
let raw: raw::ServerAclEvent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(ServerAclEvent {
content: ServerAclEventContent {
allow_ip_literals: raw.content.allow_ip_literals,
allow: raw.content.allow,
deny: raw.content.deny,
},
fn try_from(raw: raw::ServerAclEvent) -> Result<Self, Self::Error> {
Ok(Self {
content: crate::convert_content(raw.content),
event_id: raw.event_id,
origin_server_ts: raw.origin_server_ts,
prev_content: raw.prev_content.map(|prev| ServerAclEventContent {
allow_ip_literals: prev.allow_ip_literals,
allow: prev.allow,
deny: prev.deny,
}),
prev_content: raw.prev_content.map(crate::convert_content),
room_id: raw.room_id,
unsigned: raw.unsigned,
sender: raw.sender,
state_key: raw.state_key,
}))
unsigned: raw.unsigned,
})
}
}
impl TryFrom<raw::ServerAclEventContent> for ServerAclEventContent {
type Error = (raw::ServerAclEventContent, Void);
fn try_from(raw: raw::ServerAclEventContent) -> Result<Self, Self::Error> {
Ok(Self {
allow_ip_literals: raw.allow_ip_literals,
allow: raw.allow,
deny: raw.deny,
})
}
}
@ -125,37 +113,11 @@ impl Serialize for ServerAclEvent {
impl_state_event!(
ServerAclEvent,
ServerAclEventContent,
EventType::RoomServerAcl
EventType::RoomServerAcl,
raw
);
impl<'de> Deserialize<'de> for EventResult<ServerAclEventContent> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let json = serde_json::Value::deserialize(deserializer)?;
let raw: raw::ServerAclEventContent = match serde_json::from_value(json.clone()) {
Ok(raw) => raw,
Err(error) => {
return Ok(EventResult::Err(InvalidEvent(
InnerInvalidEvent::Validation {
json,
message: error.to_string(),
},
)));
}
};
Ok(EventResult::Ok(ServerAclEventContent {
allow_ip_literals: raw.allow_ip_literals,
allow: raw.allow,
deny: raw.deny,
}))
}
}
mod raw {
pub(crate) mod raw {
use super::*;
/// An event to indicate which servers are permitted to participate in the room.
@ -221,12 +183,13 @@ mod raw {
#[cfg(test)]
mod tests {
use super::ServerAclEvent;
use crate::EventResult;
#[test]
fn default_values() {
let server_acl_event: ServerAclEvent =
r#"{"content":{},"event_id":"$h29iv0s8:example.com","origin_server_ts":1,"sender":"@carl:example.com","state_key":"","type":"m.room.server_acl"}"#
.parse().unwrap();
serde_json::from_str::<EventResult<_>>(r#"{"content":{},"event_id":"$h29iv0s8:example.com","origin_server_ts":1,"sender":"@carl:example.com","state_key":"","type":"m.room.server_acl"}"#)
.unwrap().into_result().unwrap();
assert_eq!(server_acl_event.content.allow_ip_literals, true);
assert!(server_acl_event.content.allow.is_empty());

View File

@ -8,8 +8,7 @@
use std::convert::TryFrom;
use ruma_identifiers::UserId;
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::from_value;
use serde::{Serialize, Serializer};
use crate::{
room::{
@ -20,7 +19,7 @@ use crate::{
power_levels::PowerLevelsEventContent, third_party_invite::ThirdPartyInviteEventContent,
topic::TopicEventContent,
},
EventResult, EventType, InnerInvalidEvent, InvalidEvent,
EventResultCompatible, EventType,
};
/// A stripped-down version of a state event that is included along with some other events.
@ -117,194 +116,43 @@ pub type StrippedRoomThirdPartyInvite = StrippedStateContent<ThirdPartyInviteEve
/// A stripped-down version of the *m.room.topic* event.
pub type StrippedRoomTopic = StrippedStateContent<TopicEventContent>;
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)?;
impl EventResultCompatible for StrippedState {
type Raw = raw::StrippedState;
}
let event_type_value = match value.get("type") {
Some(value) => value.clone(),
None => {
return Ok(EventResult::Err(InvalidEvent(InnerInvalidEvent::Validation {
json: value,
message: "missing field `type`".to_string(),
})))
}
};
impl TryFrom<raw::StrippedState> for StrippedState {
type Error = (raw::StrippedState, 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 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))
fn try_from(raw: raw::StrippedState) -> Result<Self, Self::Error> {
unimplemented!()
}
}
/*impl<C> EventResultCompatible for StrippedStateContent<C>
where
C: EventResultCompatible,
{
type Raw = StrippedStateContent<C::Raw>;
}
// Orphan impl :(
impl<C, E> TryFrom<StrippedStateContent<C::Raw>> for StrippedStateContent<C>
where
C: EventResultCompatible,
C::Raw: TryInto<C, Error = (C::Raw, E)>,
{
type Error = (StrippedStateContent<C::Raw>, E);
fn try_from(raw: StrippedStateContent<C::Raw>) -> Result<Self, Self::Error> {
Ok(Self {
content: raw.content.try_into()?,
event_type: raw.event_type,
state_key: raw.state_key,
sender: raw.sender,
})
}
}*/
impl Serialize for StrippedState {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
@ -327,109 +175,106 @@ impl Serialize for StrippedState {
}
}
// 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)?;
mod raw {
use serde::{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))
// }
// };
use super::StrippedStateContent;
use crate::room::{
aliases::raw::AliasesEventContent, avatar::raw::AvatarEventContent,
canonical_alias::raw::CanonicalAliasEventContent, create::raw::CreateEventContent,
guest_access::raw::GuestAccessEventContent,
history_visibility::raw::HistoryVisibilityEventContent,
join_rules::raw::JoinRulesEventContent, member::raw::MemberEventContent,
name::raw::NameEventContent, power_levels::raw::PowerLevelsEventContent,
third_party_invite::raw::ThirdPartyInviteEventContent, topic::raw::TopicEventContent,
};
// 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))
// }
// };
/// A stripped-down version of the *m.room.aliases* event.
pub type StrippedRoomAliases = StrippedStateContent<AliasesEventContent>;
// 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))
// }
// };
/// A stripped-down version of the *m.room.avatar* event.
pub type StrippedRoomAvatar = StrippedStateContent<AvatarEventContent>;
// 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)),
// }
// }
// }
/// A stripped-down version of the *m.room.canonical_alias* event.
pub type StrippedRoomCanonicalAlias = StrippedStateContent<CanonicalAliasEventContent>;
// /// 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)?;
/// A stripped-down version of the *m.room.create* event.
pub type StrippedRoomCreate = StrippedStateContent<CreateEventContent>;
// 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));
// }
// },
// }))
// }
/// A stripped-down version of the *m.room.guest_access* event.
pub type StrippedRoomGuestAccess = StrippedStateContent<GuestAccessEventContent>;
/// A stripped-down version of the *m.room.history_visibility* event.
pub type StrippedRoomHistoryVisibility = StrippedStateContent<HistoryVisibilityEventContent>;
/// A stripped-down version of the *m.room.join_rules* event.
pub type StrippedRoomJoinRules = StrippedStateContent<JoinRulesEventContent>;
/// A stripped-down version of the *m.room.member* event.
pub type StrippedRoomMember = StrippedStateContent<MemberEventContent>;
/// A stripped-down version of the *m.room.name* event.
pub type StrippedRoomName = StrippedStateContent<NameEventContent>;
/// A stripped-down version of the *m.room.power_levels* event.
pub type StrippedRoomPowerLevels = StrippedStateContent<PowerLevelsEventContent>;
/// A stripped-down version of the *m.room.third_party_invite* event.
pub type StrippedRoomThirdPartyInvite = StrippedStateContent<ThirdPartyInviteEventContent>;
/// A stripped-down version of the *m.room.topic* event.
pub type StrippedRoomTopic = StrippedStateContent<TopicEventContent>;
/// A stripped-down version of a state event that is included along with some other events.
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum StrippedState {
/// A stripped-down version of the *m.room.aliases* event.
RoomAliases(StrippedRoomAliases),
/// A stripped-down version of the *m.room.avatar* event.
RoomAvatar(StrippedRoomAvatar),
/// A stripped-down version of the *m.room.canonical_alias* event.
RoomCanonicalAlias(StrippedRoomCanonicalAlias),
/// A striped-down version of the *m.room.create* event.
RoomCreate(StrippedRoomCreate),
/// A stripped-down version of the *m.room.guest_access* event.
RoomGuestAccess(StrippedRoomGuestAccess),
/// A stripped-down version of the *m.room.history_visibility* event.
RoomHistoryVisibility(StrippedRoomHistoryVisibility),
/// A stripped-down version of the *m.room.join_rules* event.
RoomJoinRules(StrippedRoomJoinRules),
/// A stripped-down version of the *m.room.member* event.
RoomMember(StrippedRoomMember),
/// A stripped-down version of the *m.room.name* event.
RoomName(StrippedRoomName),
/// A stripped-down version of the *m.room.power_levels* event.
RoomPowerLevels(StrippedRoomPowerLevels),
/// A stripped-down version of the *m.room.third_party_invite* event.
RoomThirdPartyInvite(StrippedRoomThirdPartyInvite),
/// A stripped-down version of the *m.room.topic* event.
RoomTopic(StrippedRoomTopic),
}
impl<'de> Deserialize<'de> for StrippedState {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
unimplemented!()
}
}
}
#[cfg(test)]
mod tests {
@ -442,7 +287,7 @@ mod tests {
use super::{StrippedRoomName, StrippedRoomTopic, StrippedState};
use crate::{
room::{join_rules::JoinRule, topic::TopicEventContent},
EventType,
EventResult, EventType,
};
#[test]
@ -509,7 +354,11 @@ mod tests {
}
}"#;
match name_event.parse().unwrap() {
match serde_json::from_str::<EventResult<_>>(name_event)
.unwrap()
.into_result()
.unwrap()
{
StrippedState::RoomName(event) => {
assert_eq!(event.content.name, Some("Ruma".to_string()));
assert_eq!(event.event_type, EventType::RoomName);
@ -520,9 +369,18 @@ mod tests {
};
// Ensure `StrippedStateContent` can be parsed, not just `StrippedState`.
assert!(name_event.parse::<StrippedRoomName>().is_ok());
/*assert!(
serde_json::from_str::<EventResult<StrippedRoomName>>(name_event)
.unwrap()
.into_result()
.is_ok()
);*/
match join_rules_event.parse().unwrap() {
match serde_json::from_str::<EventResult<_>>(join_rules_event)
.unwrap()
.into_result()
.unwrap()
{
StrippedState::RoomJoinRules(event) => {
assert_eq!(event.content.join_rule, JoinRule::Public);
assert_eq!(event.event_type, EventType::RoomJoinRules);
@ -532,7 +390,11 @@ mod tests {
_ => unreachable!(),
};
match avatar_event.parse().unwrap() {
match serde_json::from_str::<EventResult<_>>(avatar_event)
.unwrap()
.into_result()
.unwrap()
{
StrippedState::RoomAvatar(event) => {
let image_info = event.content.info.unwrap();