WIP
This commit is contained in:
parent
297bae4cbb
commit
05562a48a3
@ -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]
|
||||
|
@ -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)*
|
||||
|
@ -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>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
604
src/collections/raw/all.rs
Normal 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
199
src/collections/raw/only.rs
Normal 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);
|
@ -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]));
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
316
src/lib.rs
316
src/lib.rs
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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());
|
||||
|
@ -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.
|
||||
|
@ -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());
|
||||
|
438
src/stripped.rs
438
src/stripped.rs
@ -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();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user