WIP
This commit is contained in:
parent
297bae4cbb
commit
05562a48a3
@ -14,7 +14,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ruma-identifiers = "0.14.0"
|
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"
|
serde_json = "1.0.40"
|
||||||
|
|
||||||
[dependencies.js_int]
|
[dependencies.js_int]
|
||||||
|
@ -164,24 +164,11 @@ impl ToTokens for RumaEvent {
|
|||||||
|
|
||||||
let try_from_field_value = if ident == "content" {
|
let try_from_field_value = if ident == "content" {
|
||||||
match &self.content {
|
match &self.content {
|
||||||
Content::Struct(content_fields) => {
|
Content::Struct(_) => {
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
quote_spanned! {span=>
|
quote_spanned! {span=>
|
||||||
content: #content_name {
|
content: match std::convert::TryFrom::try_from(raw.content) {
|
||||||
#(#content_field_values)*
|
Ok(c) => c,
|
||||||
|
Err((_, void)) => match void {},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,25 +180,12 @@ impl ToTokens for RumaEvent {
|
|||||||
}
|
}
|
||||||
} else if ident == "prev_content" {
|
} else if ident == "prev_content" {
|
||||||
match &self.content {
|
match &self.content {
|
||||||
Content::Struct(content_fields) => {
|
Content::Struct(_) => {
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
quote_spanned! {span=>
|
quote_spanned! {span=>
|
||||||
prev_content: raw.prev_content.map(|prev| {
|
prev_content: raw.prev_content.map(|prev_content| {
|
||||||
#content_name {
|
match std::convert::TryFrom::try_from(prev_content) {
|
||||||
#(#content_field_values)*
|
Ok(c) => c,
|
||||||
|
Err((_, void)) => match void {},
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
@ -360,31 +334,19 @@ impl ToTokens for RumaEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl<'de> serde::Deserialize<'de> for crate::EventResult<#content_name> {
|
impl std::convert::TryFrom<raw::#content_name> for #content_name {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Error = (raw::#content_name, crate::Void);
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let raw: raw::#content_name = match serde_json::from_value(json.clone()) {
|
fn try_from(raw: raw::#content_name) -> Result<Self, Self::Error> {
|
||||||
Ok(raw) => raw,
|
Ok(Self {
|
||||||
Err(error) => {
|
|
||||||
return Ok(crate::EventResult::Err(crate::InvalidEvent(
|
|
||||||
crate::InnerInvalidEvent::Validation {
|
|
||||||
json,
|
|
||||||
message: error.to_string(),
|
|
||||||
},
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(crate::EventResult::Ok(#content_name {
|
|
||||||
#(#content_field_values)*
|
#(#content_field_values)*
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::EventResultCompatible for #content_name {
|
||||||
|
type Raw = raw::#content_name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TokenStream::new()
|
TokenStream::new()
|
||||||
@ -399,36 +361,25 @@ impl ToTokens for RumaEvent {
|
|||||||
|
|
||||||
#content
|
#content
|
||||||
|
|
||||||
impl<'de> serde::Deserialize<'de> for crate::EventResult<#name> {
|
impl std::convert::TryFrom<raw::#name> for #name {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Error = (raw::#name, crate::Void);
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let raw: raw::#name = match serde_json::from_value(json.clone()) {
|
fn try_from(raw: raw::#name) -> Result<Self, Self::Error> {
|
||||||
Ok(raw) => raw,
|
Ok(Self {
|
||||||
Err(error) => {
|
|
||||||
return Ok(crate::EventResult::Err(crate::InvalidEvent(
|
|
||||||
crate::InnerInvalidEvent::Validation {
|
|
||||||
json,
|
|
||||||
message: error.to_string(),
|
|
||||||
},
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(crate::EventResult::Ok(#name {
|
|
||||||
#(#try_from_field_values)*
|
#(#try_from_field_values)*
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl crate::EventResultCompatible for #name {
|
||||||
|
type Raw = raw::#name;
|
||||||
|
}
|
||||||
|
|
||||||
#impl_conversions_for_content
|
#impl_conversions_for_content
|
||||||
|
|
||||||
use serde::ser::SerializeStruct as _;
|
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>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer
|
S: serde::Serializer
|
||||||
@ -464,7 +415,7 @@ impl ToTokens for RumaEvent {
|
|||||||
#impl_state_event
|
#impl_state_event
|
||||||
|
|
||||||
/// "Raw" versions of the event and its content which implement `serde::Deserialize`.
|
/// "Raw" versions of the event and its content which implement `serde::Deserialize`.
|
||||||
mod raw {
|
pub(crate) mod raw {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#(#attrs)*
|
#(#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::{
|
use serde::{
|
||||||
de::{Error as SerdeError, Visitor},
|
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.
|
/// The result of deserializing an event, which may or may not be valid.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum EventResult<T> {
|
pub enum EventResult<T: EventResultCompatible> {
|
||||||
/// `T` deserialized and validated successfully.
|
/// `T` deserialized and validated successfully.
|
||||||
Ok(T),
|
Ok(T),
|
||||||
|
|
||||||
/// `T` deserialized but was invalid.
|
/// `T` deserialized but was invalid.
|
||||||
///
|
///
|
||||||
/// `InvalidEvent` contains the original input.
|
/// `InvalidEvent` contains the original input.
|
||||||
Err(InvalidEvent),
|
Err(InvalidEvent<T::Raw>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventResult<T> {
|
impl<T: EventResultCompatible> EventResult<T> {
|
||||||
/// Convert `EventResult<T>` into the equivalent `std::result::Result<T, InvalidEvent>`.
|
/// Convert `EventResult<T>` into the equivalent `std::result::Result<T, InvalidEvent<T::Raw>>`.
|
||||||
pub fn into_result(self) -> Result<T, InvalidEvent> {
|
pub fn into_result(self) -> Result<T, InvalidEvent<T::Raw>> {
|
||||||
match self {
|
match self {
|
||||||
EventResult::Ok(t) => Ok(t),
|
EventResult::Ok(t) => Ok(t),
|
||||||
EventResult::Err(invalid_event) => Err(invalid_event),
|
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.
|
/// A basic event.
|
||||||
pub trait Event
|
pub trait Event: Debug + Serialize + EventResultCompatible {
|
||||||
where
|
|
||||||
Self: Debug + Serialize,
|
|
||||||
{
|
|
||||||
/// The type of this event's `content` field.
|
/// The type of this event's `content` field.
|
||||||
type Content: Debug + Serialize;
|
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
|
/// 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.
|
/// `serde_json::Value` containing the raw JSON data as it was deserialized.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InvalidEvent(InnerInvalidEvent);
|
pub struct InvalidEvent<T>(InnerInvalidEvent<T>);
|
||||||
|
|
||||||
/// An event that is malformed or otherwise invalid.
|
/// An event that is malformed or otherwise invalid.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum InnerInvalidEvent {
|
enum InnerInvalidEvent<T> {
|
||||||
/// An event that deserialized but failed validation.
|
/// An event that deserialized but failed validation.
|
||||||
Validation {
|
Validation {
|
||||||
/// The raw `serde_json::Value` representation of the invalid event.
|
/// The raw `serde_json::Value` representation of the invalid event.
|
||||||
@ -169,6 +182,8 @@ enum InnerInvalidEvent {
|
|||||||
|
|
||||||
/// An message describing why the event was invalid.
|
/// An message describing why the event was invalid.
|
||||||
message: String,
|
message: String,
|
||||||
|
|
||||||
|
dummy: PhantomData<T>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
//! Enums for heterogeneous collections of events, inclusive for every event type that implements
|
//! Enums for heterogeneous collections of events, inclusive for every event type that implements
|
||||||
//! the trait of the same name.
|
//! the trait of the same name.
|
||||||
|
|
||||||
use serde::{Serialize, Serializer};
|
use std::convert::TryFrom;
|
||||||
use serde_json::{from_value, Value};
|
|
||||||
|
|
||||||
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
|
use super::raw::all as raw;
|
||||||
use crate::{
|
use crate::{
|
||||||
call::{
|
call::{
|
||||||
answer::AnswerEvent, candidates::CandidatesEvent, hangup::HangupEvent, invite::InviteEvent,
|
answer::AnswerEvent, candidates::CandidatesEvent, hangup::HangupEvent, invite::InviteEvent,
|
||||||
@ -46,7 +48,7 @@ use crate::{
|
|||||||
sticker::StickerEvent,
|
sticker::StickerEvent,
|
||||||
tag::TagEvent,
|
tag::TagEvent,
|
||||||
typing::TypingEvent,
|
typing::TypingEvent,
|
||||||
CustomEvent, CustomRoomEvent, CustomStateEvent, EventType, InnerInvalidEvent, InvalidEvent,
|
CustomEvent, CustomRoomEvent, CustomStateEvent, EventResultCompatible, Void,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A basic event, room event, or state event.
|
/// A basic event, room event, or state event.
|
||||||
@ -334,6 +336,42 @@ pub enum StateEvent {
|
|||||||
CustomState(CustomStateEvent),
|
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 {
|
impl Serialize for Event {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
//! Enums for heterogeneous collections of events, exclusive to event types that implement "at
|
//! Enums for heterogeneous collections of events, exclusive to event types that implement "at
|
||||||
//! most" the trait of the same name.
|
//! most" the trait of the same name.
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use serde::{Serialize, Serializer};
|
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::{
|
use crate::{
|
||||||
call::{
|
call::{
|
||||||
answer::AnswerEvent, candidates::CandidatesEvent, hangup::HangupEvent, invite::InviteEvent,
|
answer::AnswerEvent, candidates::CandidatesEvent, hangup::HangupEvent, invite::InviteEvent,
|
||||||
@ -33,7 +32,7 @@ use crate::{
|
|||||||
sticker::StickerEvent,
|
sticker::StickerEvent,
|
||||||
tag::TagEvent,
|
tag::TagEvent,
|
||||||
typing::TypingEvent,
|
typing::TypingEvent,
|
||||||
CustomEvent, CustomRoomEvent, EventType, InnerInvalidEvent, InvalidEvent,
|
CustomEvent, CustomRoomEvent, EventResultCompatible, Void,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A basic event.
|
/// A basic event.
|
||||||
@ -133,6 +132,30 @@ pub enum RoomEvent {
|
|||||||
CustomRoom(CustomRoomEvent),
|
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 {
|
impl Serialize for Event {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
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 serde_json::to_string;
|
||||||
|
|
||||||
use super::{DirectEvent, DirectEventContent};
|
use super::{DirectEvent, DirectEventContent};
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialization() {
|
fn serialization() {
|
||||||
@ -67,7 +68,10 @@ mod tests {
|
|||||||
rooms[1].to_string()
|
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();
|
let direct_rooms = event.content.get(&alice).unwrap();
|
||||||
|
|
||||||
assert!(direct_rooms.contains(&rooms[0]));
|
assert!(direct_rooms.contains(&rooms[0]));
|
||||||
|
@ -27,6 +27,7 @@ ruma_event! {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{DummyEvent, Empty};
|
use super::{DummyEvent, Empty};
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialization() {
|
fn serialization() {
|
||||||
@ -42,6 +43,9 @@ mod tests {
|
|||||||
fn deserialization() {
|
fn deserialization() {
|
||||||
let json = r#"{"content":{},"type":"m.dummy"}"#;
|
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.
|
//! Types for the *m.ignored_user_list* event.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use ruma_identifiers::UserId;
|
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.
|
/// A list of users to ignore.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@ -15,36 +15,29 @@ pub struct IgnoredUserListEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The payload for `IgnoredUserListEvent`.
|
/// The payload for `IgnoredUserListEvent`.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize)]
|
||||||
pub struct IgnoredUserListEventContent {
|
pub struct IgnoredUserListEventContent {
|
||||||
/// A list of users to ignore.
|
/// A list of users to ignore.
|
||||||
pub ignored_users: Vec<UserId>,
|
pub ignored_users: Vec<UserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<IgnoredUserListEvent> {
|
impl TryFrom<raw::IgnoredUserListEvent> for IgnoredUserListEvent {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Error = (raw::IgnoredUserListEvent, Void);
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let raw: raw::IgnoredUserListEvent = match serde_json::from_value(json.clone()) {
|
fn try_from(raw: raw::IgnoredUserListEvent) -> Result<Self, Self::Error> {
|
||||||
Ok(raw) => raw,
|
Ok(Self {
|
||||||
Err(error) => {
|
content: crate::convert_content(raw.content),
|
||||||
return Ok(EventResult::Err(InvalidEvent(
|
})
|
||||||
InnerInvalidEvent::Validation {
|
}
|
||||||
json,
|
}
|
||||||
message: error.to_string(),
|
|
||||||
},
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(EventResult::Ok(IgnoredUserListEvent {
|
impl TryFrom<raw::IgnoredUserListEventContent> for IgnoredUserListEventContent {
|
||||||
content: IgnoredUserListEventContent {
|
type Error = (raw::IgnoredUserListEventContent, Void);
|
||||||
ignored_users: raw.content.ignored_users.keys().cloned().collect(),
|
|
||||||
},
|
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!(
|
impl_event!(
|
||||||
IgnoredUserListEvent,
|
IgnoredUserListEvent,
|
||||||
IgnoredUserListEventContent,
|
IgnoredUserListEventContent,
|
||||||
EventType::IgnoredUserList
|
EventType::IgnoredUserList,
|
||||||
|
raw
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<IgnoredUserListEventContent> {
|
pub(crate) mod raw {
|
||||||
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 {
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::Empty;
|
|
||||||
|
|
||||||
/// A list of users to ignore.
|
/// A list of users to ignore.
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
@ -125,7 +76,8 @@ mod raw {
|
|||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct IgnoredUserListEventContent {
|
pub struct IgnoredUserListEventContent {
|
||||||
/// A list of users to ignore.
|
/// 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 ruma_identifiers::UserId;
|
||||||
|
|
||||||
use super::{EventResult, IgnoredUserListEvent, IgnoredUserListEventContent};
|
use super::{IgnoredUserListEvent, IgnoredUserListEventContent};
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialization() {
|
fn serialization() {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
//! Types for the *m.key.verification.start* event.
|
//! Types for the *m.key.verification.start* event.
|
||||||
|
|
||||||
|
use std::convert::{TryFrom, TryInto as _};
|
||||||
|
|
||||||
use ruma_identifiers::DeviceId;
|
use ruma_identifiers::DeviceId;
|
||||||
use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde_json::{from_value, Value};
|
use serde_json::{from_value, Value};
|
||||||
@ -8,7 +10,7 @@ use super::{
|
|||||||
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, ShortAuthenticationString,
|
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, ShortAuthenticationString,
|
||||||
VerificationMethod,
|
VerificationMethod,
|
||||||
};
|
};
|
||||||
use crate::{Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent, InvalidInput};
|
use crate::{Event, EventType, InvalidInput};
|
||||||
|
|
||||||
/// Begins an SAS key verification process.
|
/// Begins an SAS key verification process.
|
||||||
///
|
///
|
||||||
@ -31,38 +33,14 @@ pub enum StartEventContent {
|
|||||||
__Nonexhaustive,
|
__Nonexhaustive,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<StartEvent> {
|
impl TryFrom<raw::StartEvent> for StartEvent {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Error = (raw::StartEvent, &'static str);
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let raw: raw::StartEvent = match serde_json::from_value(json.clone()) {
|
fn try_from(raw: raw::StartEvent) -> Result<Self, Self::Error> {
|
||||||
Ok(raw) => raw,
|
match raw.content.try_into() {
|
||||||
Err(error) => {
|
Ok(content) => Ok(Self { content }),
|
||||||
return Ok(EventResult::Err(InvalidEvent(
|
Err((content, msg)) => Err((raw::StartEvent { content }, msg)),
|
||||||
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 }))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,78 +61,62 @@ impl Serialize for StartEvent {
|
|||||||
impl_event!(
|
impl_event!(
|
||||||
StartEvent,
|
StartEvent,
|
||||||
StartEventContent,
|
StartEventContent,
|
||||||
EventType::KeyVerificationStart
|
EventType::KeyVerificationStart,
|
||||||
|
raw
|
||||||
);
|
);
|
||||||
|
|
||||||
impl StartEventContent {
|
impl TryFrom<raw::StartEventContent> for StartEventContent {
|
||||||
fn from_raw(raw: raw::StartEventContent) -> Result<Self, &'static str> {
|
type Error = (raw::StartEventContent, &'static str);
|
||||||
|
|
||||||
|
fn try_from(raw: raw::StartEventContent) -> Result<Self, Self::Error> {
|
||||||
match raw {
|
match raw {
|
||||||
raw::StartEventContent::MSasV1(content) => {
|
raw::StartEventContent::MSasV1(content) => {
|
||||||
if !content
|
if !content
|
||||||
.key_agreement_protocols
|
.key_agreement_protocols
|
||||||
.contains(&KeyAgreementProtocol::Curve25519)
|
.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) {
|
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
|
if !content
|
||||||
.message_authentication_codes
|
.message_authentication_codes
|
||||||
.contains(&MessageAuthenticationCode::HkdfHmacSha256)
|
.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
|
if !content
|
||||||
.short_authentication_string
|
.short_authentication_string
|
||||||
.contains(&ShortAuthenticationString::Decimal)
|
.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))
|
Ok(StartEventContent::MSasV1(content))
|
||||||
}
|
}
|
||||||
raw::StartEventContent::__Nonexhaustive => {
|
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 {
|
impl Serialize for StartEventContent {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@ -167,7 +129,7 @@ impl Serialize for StartEventContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod raw {
|
pub(crate) mod raw {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Begins an SAS key verification process.
|
/// Begins an SAS key verification process.
|
||||||
@ -374,9 +336,10 @@ mod tests {
|
|||||||
use serde_json::to_string;
|
use serde_json::to_string;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
EventResult, HashAlgorithm, KeyAgreementProtocol, MSasV1Content, MSasV1ContentOptions,
|
HashAlgorithm, KeyAgreementProtocol, MSasV1Content, MSasV1ContentOptions,
|
||||||
MessageAuthenticationCode, ShortAuthenticationString, StartEvent, StartEventContent,
|
MessageAuthenticationCode, ShortAuthenticationString, StartEvent, StartEventContent,
|
||||||
};
|
};
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invalid_m_sas_v1_content_missing_required_key_agreement_protocols() {
|
fn invalid_m_sas_v1_content_missing_required_key_agreement_protocols() {
|
||||||
@ -536,7 +499,7 @@ mod tests {
|
|||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
assert!(error.message().contains("key_agreement_protocols"));
|
assert!(error.message().contains("key_agreement_protocols"));
|
||||||
assert!(error.json().is_some());
|
assert!(error.raw_data().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -550,7 +513,7 @@ mod tests {
|
|||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
assert!(error.message().contains("hashes"));
|
assert!(error.message().contains("hashes"));
|
||||||
assert!(error.json().is_some());
|
assert!(error.raw_data().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -564,7 +527,7 @@ mod tests {
|
|||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
assert!(error.message().contains("message_authentication_codes"));
|
assert!(error.message().contains("message_authentication_codes"));
|
||||||
assert!(error.json().is_some());
|
assert!(error.raw_data().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -578,7 +541,7 @@ mod tests {
|
|||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
assert!(error.message().contains("short_authentication_string"));
|
assert!(error.message().contains("short_authentication_string"));
|
||||||
assert!(error.json().is_some());
|
assert!(error.raw_data().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -593,6 +556,6 @@ mod tests {
|
|||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
assert!(error.message().contains("key_agreement_protocols"));
|
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_debug_implementations)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![deny(warnings)]
|
//#![deny(warnings)]
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
convert::TryInto,
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt::{Debug, Display, Error as FmtError, Formatter, Result as FmtResult},
|
fmt::{Debug, Display, Error as FmtError, Formatter, Result as FmtResult},
|
||||||
hash::Hash,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||||
use serde::{
|
use serde::{
|
||||||
de::{Error as SerdeError, IntoDeserializer, MapAccess, Visitor},
|
de::{DeserializeOwned, Error as SerdeError, IntoDeserializer, MapAccess, Visitor},
|
||||||
ser::SerializeMap,
|
ser::SerializeMap,
|
||||||
Deserialize, Deserializer, Serialize, Serializer,
|
Deserialize, Deserializer, Serialize, Serializer,
|
||||||
};
|
};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
// pub use custom::CustomEvent;
|
pub use custom::CustomEvent;
|
||||||
// pub use custom_room::CustomRoomEvent;
|
pub use custom_room::CustomRoomEvent;
|
||||||
// pub use custom_state::CustomStateEvent;
|
pub use custom_state::CustomStateEvent;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
pub mod call;
|
pub mod call;
|
||||||
// /// Enums for heterogeneous collections of events.
|
/// Enums for heterogeneous collections of events.
|
||||||
// pub mod collections {
|
pub mod collections {
|
||||||
// pub mod all;
|
pub mod all;
|
||||||
// pub mod only;
|
pub mod only;
|
||||||
// }
|
|
||||||
|
mod raw {
|
||||||
|
pub mod all;
|
||||||
|
pub mod only;
|
||||||
|
}
|
||||||
|
}
|
||||||
pub mod direct;
|
pub mod direct;
|
||||||
pub mod dummy;
|
pub mod dummy;
|
||||||
pub mod forwarded_room_key;
|
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
|
/// 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
|
/// 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.
|
/// `serde_json::Value` containing the raw JSON data as it was deserialized.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct InvalidEvent(InnerInvalidEvent);
|
pub struct InvalidEvent<T>(InnerInvalidEvent<T>);
|
||||||
|
|
||||||
impl InvalidEvent {
|
impl<T> InvalidEvent<T> {
|
||||||
/// A message describing why the event is invalid.
|
/// A message describing why the event is invalid.
|
||||||
pub fn message(&self) -> String {
|
pub fn message(&self) -> String {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
InnerInvalidEvent::Deserialization { ref error } => error.to_string(),
|
InnerInvalidEvent::Deserialization { ref error, .. } => error.to_string(),
|
||||||
InnerInvalidEvent::Validation { ref message, .. } => message.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> {
|
pub fn json(&self) -> Option<&Value> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
InnerInvalidEvent::Validation { ref json, .. } => Some(json),
|
InnerInvalidEvent::Deserialization { ref json, .. } => Some(json),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for InvalidEvent {
|
impl<T> Display for InvalidEvent<T> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
write!(f, "{}", self.message())
|
write!(f, "{}", self.message())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for InvalidEvent {}
|
impl<T: Debug> Error for InvalidEvent<T> {}
|
||||||
|
|
||||||
/// An event that is malformed or otherwise invalid.
|
/// An event that is malformed or otherwise invalid.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum InnerInvalidEvent {
|
enum InnerInvalidEvent<T> {
|
||||||
/// An event that failed to deserialize from JSON.
|
/// An event that failed to deserialize from JSON.
|
||||||
Deserialization {
|
Deserialization {
|
||||||
|
/// The raw `serde_json::Value` representation of the invalid event.
|
||||||
|
json: Value,
|
||||||
|
|
||||||
/// The deserialization error returned by serde.
|
/// The deserialization error returned by serde.
|
||||||
error: serde_json::Error,
|
error: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// An event that deserialized but failed validation.
|
/// An event that deserialized but failed validation.
|
||||||
Validation {
|
Validation {
|
||||||
/// The raw `serde_json::Value` representation of the invalid event.
|
/// The event data that failed validation.
|
||||||
json: Value,
|
raw_data: T,
|
||||||
|
|
||||||
/// An message describing why the event was invalid.
|
/// An message describing why the event was invalid.
|
||||||
message: String,
|
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.
|
/// 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
|
/// 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 {}
|
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.
|
/// 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
|
/// 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,
|
/// 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
|
/// this structure will contain an `InvalidEvent`. See the documentation for `InvalidEvent` for
|
||||||
/// more details.
|
/// more details.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum EventResult<T> {
|
pub enum EventResult<T: EventResultCompatible> {
|
||||||
/// `T` deserialized and validated successfully.
|
/// `T` deserialized and validated successfully.
|
||||||
Ok(T),
|
Ok(T),
|
||||||
|
|
||||||
/// `T` deserialized but was invalid.
|
/// `T` failed either deserialization or validation.
|
||||||
///
|
///
|
||||||
/// `InvalidEvent` contains the original input.
|
/// `InvalidEvent` contains the error message and the raw data.
|
||||||
Err(InvalidEvent),
|
Err(InvalidEvent<T::Raw>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> EventResult<T> {
|
impl<T: EventResultCompatible> EventResult<T> {
|
||||||
/// Convert `EventResult<T>` into the equivalent `std::result::Result<T, InvalidEvent>`.
|
/// 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 {
|
match self {
|
||||||
EventResult::Ok(t) => Ok(t),
|
EventResult::Ok(t) => Ok(t),
|
||||||
EventResult::Err(invalid_event) => Err(invalid_event),
|
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
|
where
|
||||||
K: for<'inner> Deserialize<'inner> + Eq + Hash,
|
T: EventResultCompatible,
|
||||||
V: for<'inner> Deserialize<'inner>,
|
T::Raw: TryInto<T, Error = (T::Raw, E)>,
|
||||||
|
E: Into<String>,
|
||||||
{
|
{
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
@ -285,19 +311,36 @@ where
|
|||||||
{
|
{
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
let json = serde_json::Value::deserialize(deserializer)?;
|
||||||
|
|
||||||
let hash_map: HashMap<K, V> = match serde_json::from_value(json.clone()) {
|
let raw_data: T::Raw = match serde_json::from_value(json.clone()) {
|
||||||
Ok(hash_map) => hash_map,
|
Ok(raw) => raw,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
return Ok(EventResult::Err(InvalidEvent(
|
return Ok(EventResult::Err(InvalidEvent(
|
||||||
InnerInvalidEvent::Validation {
|
InnerInvalidEvent::Deserialization {
|
||||||
json,
|
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.
|
/// The type of an event.
|
||||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
pub enum EventType {
|
pub enum EventType {
|
||||||
@ -523,12 +543,7 @@ pub enum EventType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A basic event.
|
/// A basic event.
|
||||||
pub trait Event
|
pub trait Event: Debug + Serialize + Sized + EventResultCompatible {
|
||||||
where
|
|
||||||
Self: Debug + Serialize + Sized,
|
|
||||||
for<'de> EventResult<Self>: Deserialize<'de>,
|
|
||||||
for<'de> EventResult<Self::Content>: Deserialize<'de>,
|
|
||||||
{
|
|
||||||
/// The type of this event's `content` field.
|
/// The type of this event's `content` field.
|
||||||
type Content: Debug + Serialize;
|
type Content: Debug + Serialize;
|
||||||
|
|
||||||
@ -540,11 +555,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An event within the context of a room.
|
/// An event within the context of a room.
|
||||||
pub trait RoomEvent: Event
|
pub trait RoomEvent: Event {
|
||||||
where
|
|
||||||
for<'de> EventResult<Self>: Deserialize<'de>,
|
|
||||||
for<'de> EventResult<<Self as Event>::Content>: Deserialize<'de>,
|
|
||||||
{
|
|
||||||
/// The unique identifier for the event.
|
/// The unique identifier for the event.
|
||||||
fn event_id(&self) -> &EventId;
|
fn event_id(&self) -> &EventId;
|
||||||
|
|
||||||
@ -566,11 +577,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An event that describes persistent state about a room.
|
/// An event that describes persistent state about a room.
|
||||||
pub trait StateEvent: RoomEvent
|
pub trait StateEvent: RoomEvent {
|
||||||
where
|
|
||||||
for<'de> EventResult<Self>: Deserialize<'de>,
|
|
||||||
for<'de> EventResult<<Self as Event>::Content>: Deserialize<'de>,
|
|
||||||
{
|
|
||||||
/// The previous content for this state key, if any.
|
/// The previous content for this state key, if any.
|
||||||
fn prev_content(&self) -> Option<&Self::Content>;
|
fn prev_content(&self) -> Option<&Self::Content>;
|
||||||
|
|
||||||
@ -578,56 +585,56 @@ where
|
|||||||
fn state_key(&self) -> &str;
|
fn state_key(&self) -> &str;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mod custom {
|
mod custom {
|
||||||
// use ruma_events_macros::ruma_event;
|
use ruma_events_macros::ruma_event;
|
||||||
// use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
// ruma_event! {
|
ruma_event! {
|
||||||
// /// A custom basic event not covered by the Matrix specification.
|
/// A custom basic event not covered by the Matrix specification.
|
||||||
// CustomEvent {
|
CustomEvent {
|
||||||
// kind: Event,
|
kind: Event,
|
||||||
// event_type: Custom,
|
event_type: Custom,
|
||||||
// content_type_alias: {
|
content_type_alias: {
|
||||||
// /// The payload for `CustomEvent`.
|
/// The payload for `CustomEvent`.
|
||||||
// Value
|
Value
|
||||||
// },
|
},
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// mod custom_room {
|
mod custom_room {
|
||||||
// use ruma_events_macros::ruma_event;
|
use ruma_events_macros::ruma_event;
|
||||||
// use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
// ruma_event! {
|
ruma_event! {
|
||||||
// /// A custom room event not covered by the Matrix specification.
|
/// A custom room event not covered by the Matrix specification.
|
||||||
// CustomRoomEvent {
|
CustomRoomEvent {
|
||||||
// kind: RoomEvent,
|
kind: RoomEvent,
|
||||||
// event_type: Custom,
|
event_type: Custom,
|
||||||
// content_type_alias: {
|
content_type_alias: {
|
||||||
// /// The payload for `CustomRoomEvent`.
|
/// The payload for `CustomRoomEvent`.
|
||||||
// Value
|
Value
|
||||||
// },
|
},
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// mod custom_state {
|
mod custom_state {
|
||||||
// use ruma_events_macros::ruma_event;
|
use ruma_events_macros::ruma_event;
|
||||||
// use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
// ruma_event! {
|
ruma_event! {
|
||||||
// /// A custom state event not covered by the Matrix specification.
|
/// A custom state event not covered by the Matrix specification.
|
||||||
// CustomStateEvent {
|
CustomStateEvent {
|
||||||
// kind: StateEvent,
|
kind: StateEvent,
|
||||||
// event_type: Custom,
|
event_type: Custom,
|
||||||
// content_type_alias: {
|
content_type_alias: {
|
||||||
// /// The payload for `CustomStateEvent`.
|
/// The payload for `CustomStateEvent`.
|
||||||
// Value
|
Value
|
||||||
// },
|
},
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
impl Display for EventType {
|
impl Display for EventType {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
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.
|
/// Used to default the `bool` fields to `true` during deserialization.
|
||||||
fn default_true() -> bool {
|
fn default_true() -> bool {
|
||||||
true
|
true
|
||||||
|
@ -25,8 +25,16 @@ macro_rules! impl_enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_event {
|
macro_rules! impl_event {
|
||||||
($name:ident, $content_name:ident, $event_type:path) => {
|
($name:ident, $content_name:ident, $event_type:path, $raw_mod:ident) => {
|
||||||
impl Event for $name {
|
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.
|
/// The type of this event's `content` field.
|
||||||
type Content = $content_name;
|
type Content = $content_name;
|
||||||
|
|
||||||
@ -36,7 +44,7 @@ macro_rules! impl_event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The type of the event.
|
/// The type of the event.
|
||||||
fn event_type(&self) -> EventType {
|
fn event_type(&self) -> crate::EventType {
|
||||||
$event_type
|
$event_type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,8 +52,8 @@ macro_rules! impl_event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_room_event {
|
macro_rules! impl_room_event {
|
||||||
($name:ident, $content_name:ident, $event_type:path) => {
|
($name:ident, $content_name:ident, $event_type:path, $raw_mod:ident) => {
|
||||||
impl_event!($name, $content_name, $event_type);
|
impl_event!($name, $content_name, $event_type, $raw_mod);
|
||||||
|
|
||||||
impl RoomEvent for $name {
|
impl RoomEvent for $name {
|
||||||
/// The unique identifier for the event.
|
/// The unique identifier for the event.
|
||||||
@ -81,8 +89,8 @@ macro_rules! impl_room_event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_state_event {
|
macro_rules! impl_state_event {
|
||||||
($name:ident, $content_name:ident, $event_type:path) => {
|
($name:ident, $content_name:ident, $event_type:path, $raw_mod:ident) => {
|
||||||
impl_room_event!($name, $content_name, $event_type);
|
impl_room_event!($name, $content_name, $event_type, $raw_mod);
|
||||||
|
|
||||||
impl StateEvent for $name {
|
impl StateEvent for $name {
|
||||||
/// The previous content for this state key, if any.
|
/// The previous content for this state key, if any.
|
||||||
|
@ -80,6 +80,7 @@ mod tests {
|
|||||||
use serde_json::to_string;
|
use serde_json::to_string;
|
||||||
|
|
||||||
use super::{PresenceEvent, PresenceEventContent, PresenceState};
|
use super::{PresenceEvent, PresenceEventContent, PresenceState};
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialization() {
|
fn serialization() {
|
||||||
@ -118,6 +119,12 @@ mod tests {
|
|||||||
let json =
|
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"}"#;
|
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,
|
Action, EventMatchCondition, PushCondition, PushRulesEvent, RoomMemberCountCondition,
|
||||||
SenderNotificationPermissionCondition, Tweak,
|
SenderNotificationPermissionCondition, Tweak,
|
||||||
};
|
};
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_string_action() {
|
fn serialize_string_action() {
|
||||||
@ -776,6 +777,9 @@ mod tests {
|
|||||||
},
|
},
|
||||||
"type": "m.push_rules"
|
"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.
|
//! Types for the *m.room.canonical_alias* event.
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_identifiers::{EventId, RoomAliasId, RoomId, UserId};
|
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 serde_json::Value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{empty_string_as_none, Event, EventType, RoomEvent, StateEvent, Void};
|
||||||
empty_string_as_none, Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent,
|
|
||||||
RoomEvent, StateEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Informs the room as to which alias is the canonical one.
|
/// Informs the room as to which alias is the canonical one.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@ -48,39 +47,28 @@ pub struct CanonicalAliasEventContent {
|
|||||||
pub alias: Option<RoomAliasId>,
|
pub alias: Option<RoomAliasId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<CanonicalAliasEvent> {
|
impl TryFrom<raw::CanonicalAliasEvent> for CanonicalAliasEvent {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Error = (raw::CanonicalAliasEvent, Void);
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let raw: raw::CanonicalAliasEvent = match serde_json::from_value(json.clone()) {
|
fn try_from(raw: raw::CanonicalAliasEvent) -> Result<Self, Self::Error> {
|
||||||
Ok(raw) => raw,
|
Ok(Self {
|
||||||
Err(error) => {
|
content: crate::convert_content(raw.content),
|
||||||
return Ok(EventResult::Err(InvalidEvent(
|
|
||||||
InnerInvalidEvent::Validation {
|
|
||||||
json,
|
|
||||||
message: error.to_string(),
|
|
||||||
},
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(EventResult::Ok(CanonicalAliasEvent {
|
|
||||||
content: CanonicalAliasEventContent {
|
|
||||||
alias: raw.content.alias,
|
|
||||||
},
|
|
||||||
event_id: raw.event_id,
|
event_id: raw.event_id,
|
||||||
origin_server_ts: raw.origin_server_ts,
|
origin_server_ts: raw.origin_server_ts,
|
||||||
prev_content: raw
|
prev_content: raw.prev_content.map(crate::convert_content),
|
||||||
.prev_content
|
|
||||||
.map(|prev| CanonicalAliasEventContent { alias: prev.alias }),
|
|
||||||
room_id: raw.room_id,
|
room_id: raw.room_id,
|
||||||
sender: raw.sender,
|
sender: raw.sender,
|
||||||
state_key: raw.state_key,
|
state_key: raw.state_key,
|
||||||
unsigned: raw.unsigned,
|
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!(
|
impl_state_event!(
|
||||||
CanonicalAliasEvent,
|
CanonicalAliasEvent,
|
||||||
CanonicalAliasEventContent,
|
CanonicalAliasEventContent,
|
||||||
EventType::RoomCanonicalAlias
|
EventType::RoomCanonicalAlias,
|
||||||
|
raw
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<CanonicalAliasEventContent> {
|
pub(crate) mod raw {
|
||||||
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 {
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Informs the room as to which alias is the canonical one.
|
/// Informs the room as to which alias is the canonical one.
|
||||||
@ -213,7 +177,8 @@ mod tests {
|
|||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_identifiers::{EventId, RoomAliasId, UserId};
|
use ruma_identifiers::{EventId, RoomAliasId, UserId};
|
||||||
|
|
||||||
use super::{CanonicalAliasEvent, CanonicalAliasEventContent, EventResult};
|
use super::{CanonicalAliasEvent, CanonicalAliasEventContent};
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialization_with_optional_fields_as_none() {
|
fn serialization_with_optional_fields_as_none() {
|
||||||
|
@ -56,6 +56,7 @@ mod tests {
|
|||||||
use ruma_identifiers::{RoomVersionId, UserId};
|
use ruma_identifiers::{RoomVersionId, UserId};
|
||||||
|
|
||||||
use super::CreateEventContent;
|
use super::CreateEventContent;
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialization() {
|
fn serialization() {
|
||||||
@ -82,6 +83,12 @@ mod tests {
|
|||||||
|
|
||||||
let json = r#"{"creator":"@carl:example.com","m.federate":true,"room_version":"4"}"#;
|
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.
|
//! Types for the *m.room.encrypted* event.
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_identifiers::{DeviceId, EventId, RoomId, UserId};
|
use ruma_identifiers::{DeviceId, EventId, RoomId, UserId};
|
||||||
use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde_json::{from_value, Value};
|
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.
|
/// This event type is used when sending encrypted events.
|
||||||
///
|
///
|
||||||
@ -48,45 +50,34 @@ pub enum EncryptedEventContent {
|
|||||||
__Nonexhaustive,
|
__Nonexhaustive,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<EncryptedEvent> {
|
impl TryFrom<raw::EncryptedEvent> for EncryptedEvent {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Error = (raw::EncryptedEvent, Void);
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let raw: raw::EncryptedEvent = match serde_json::from_value(json.clone()) {
|
fn try_from(raw: raw::EncryptedEvent) -> Result<Self, Self::Error> {
|
||||||
Ok(raw) => raw,
|
Ok(Self {
|
||||||
Err(error) => {
|
content: crate::convert_content(raw.content),
|
||||||
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,
|
|
||||||
event_id: raw.event_id,
|
event_id: raw.event_id,
|
||||||
origin_server_ts: raw.origin_server_ts,
|
origin_server_ts: raw.origin_server_ts,
|
||||||
room_id: raw.room_id,
|
room_id: raw.room_id,
|
||||||
sender: raw.sender,
|
sender: raw.sender,
|
||||||
unsigned: raw.unsigned,
|
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!(
|
impl_room_event!(
|
||||||
EncryptedEvent,
|
EncryptedEvent,
|
||||||
EncryptedEventContent,
|
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 {
|
impl Serialize for EncryptedEventContent {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@ -180,7 +139,7 @@ impl Serialize for EncryptedEventContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod raw {
|
pub(crate) mod raw {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// This event type is used when sending encrypted events.
|
/// This event type is used when sending encrypted events.
|
||||||
@ -318,7 +277,8 @@ pub struct MegolmV1AesSha2Content {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use serde_json::to_string;
|
use serde_json::to_string;
|
||||||
|
|
||||||
use super::{Algorithm, EncryptedEventContent, EventResult, MegolmV1AesSha2Content};
|
use super::{Algorithm, EncryptedEventContent, MegolmV1AesSha2Content};
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serializtion() {
|
fn serializtion() {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
//! Types for the *m.room.message* event.
|
//! Types for the *m.room.message* event.
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||||
use serde::{
|
use serde::{
|
||||||
@ -10,7 +12,7 @@ use serde::{
|
|||||||
use serde_json::{from_value, Value};
|
use serde_json::{from_value, Value};
|
||||||
|
|
||||||
use super::{EncryptedFile, ImageInfo, ThumbnailInfo};
|
use super::{EncryptedFile, ImageInfo, ThumbnailInfo};
|
||||||
use crate::{Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent, RoomEvent};
|
use crate::{Event, EventType, RoomEvent, Void};
|
||||||
|
|
||||||
pub mod feedback;
|
pub mod feedback;
|
||||||
|
|
||||||
@ -74,50 +76,41 @@ pub enum MessageEventContent {
|
|||||||
__Nonexhaustive,
|
__Nonexhaustive,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<MessageEvent> {
|
impl TryFrom<raw::MessageEvent> for MessageEvent {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Error = (raw::MessageEvent, Void);
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let raw: raw::MessageEvent = match serde_json::from_value(json.clone()) {
|
fn try_from(raw: raw::MessageEvent) -> Result<Self, Self::Error> {
|
||||||
Ok(raw) => raw,
|
Ok(Self {
|
||||||
Err(error) => {
|
content: crate::convert_content(raw.content),
|
||||||
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.")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
event_id: raw.event_id,
|
event_id: raw.event_id,
|
||||||
origin_server_ts: raw.origin_server_ts,
|
origin_server_ts: raw.origin_server_ts,
|
||||||
room_id: raw.room_id,
|
room_id: raw.room_id,
|
||||||
sender: raw.sender,
|
sender: raw.sender,
|
||||||
unsigned: raw.unsigned,
|
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 {
|
impl Serialize for MessageEventContent {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
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> {
|
pub(crate) mod raw {
|
||||||
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 {
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A message sent to a room.
|
/// A message sent to a room.
|
||||||
@ -1085,7 +1043,8 @@ impl Serialize for VideoMessageEventContent {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use serde_json::to_string;
|
use serde_json::to_string;
|
||||||
|
|
||||||
use super::{AudioMessageEventContent, EventResult, MessageEventContent};
|
use super::{AudioMessageEventContent, MessageEventContent};
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialization() {
|
fn serialization() {
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
//! Types for the *m.room.name* event.
|
//! Types for the *m.room.name* event.
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
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 serde_json::Value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
empty_string_as_none, Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent,
|
empty_string_as_none, Event as _, EventType, InvalidInput, RoomEvent, StateEvent, Void,
|
||||||
InvalidInput, RoomEvent, StateEvent,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A human-friendly room name designed to be displayed to the end-user.
|
/// 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>,
|
pub(crate) name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<NameEvent> {
|
impl TryFrom<raw::NameEvent> for NameEvent {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Error = (raw::NameEvent, Void);
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let raw: raw::NameEvent = match serde_json::from_value(json.clone()) {
|
fn try_from(raw: raw::NameEvent) -> Result<Self, Self::Error> {
|
||||||
Ok(raw) => raw,
|
Ok(Self {
|
||||||
Err(error) => {
|
content: crate::convert_content(raw.content),
|
||||||
return Ok(EventResult::Err(InvalidEvent(
|
|
||||||
InnerInvalidEvent::Validation {
|
|
||||||
json,
|
|
||||||
message: error.to_string(),
|
|
||||||
},
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(EventResult::Ok(NameEvent {
|
|
||||||
content: NameEventContent {
|
|
||||||
name: raw.content.name,
|
|
||||||
},
|
|
||||||
event_id: raw.event_id,
|
event_id: raw.event_id,
|
||||||
origin_server_ts: raw.origin_server_ts,
|
origin_server_ts: raw.origin_server_ts,
|
||||||
prev_content: raw
|
prev_content: raw.prev_content.map(crate::convert_content),
|
||||||
.prev_content
|
|
||||||
.map(|prev| NameEventContent { name: prev.name }),
|
|
||||||
room_id: raw.room_id,
|
room_id: raw.room_id,
|
||||||
sender: raw.sender,
|
sender: raw.sender,
|
||||||
state_key: raw.state_key,
|
state_key: raw.state_key,
|
||||||
unsigned: raw.unsigned,
|
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 {
|
impl NameEventContent {
|
||||||
/// Create a new `NameEventContent` with the given name.
|
/// Create a new `NameEventContent` with the given name.
|
||||||
@ -151,30 +141,7 @@ impl NameEventContent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<NameEventContent> {
|
pub(crate) mod raw {
|
||||||
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 {
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// A human-friendly room name designed to be displayed to the end-user.
|
/// 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 ruma_identifiers::{EventId, RoomId, UserId};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use super::{EventResult, NameEvent, NameEventContent};
|
use super::{NameEvent, NameEventContent};
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialization_with_optional_fields_as_none() {
|
fn serialization_with_optional_fields_as_none() {
|
||||||
|
@ -25,7 +25,7 @@ mod tests {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
room::pinned_events::{PinnedEventsEvent, PinnedEventsEventContent},
|
room::pinned_events::{PinnedEventsEvent, PinnedEventsEventContent},
|
||||||
Event, RoomEvent, StateEvent,
|
Event, EventResult, RoomEvent, StateEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -47,7 +47,11 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let serialized_event = to_string(&event).unwrap();
|
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.event_id(), event.event_id());
|
||||||
assert_eq!(parsed_event.room_id(), event.room_id());
|
assert_eq!(parsed_event.room_id(), event.room_id());
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
//! Types for the *m.room.power_levels* event.
|
//! Types for the *m.room.power_levels* event.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, convert::TryFrom};
|
||||||
|
|
||||||
use js_int::{Int, UInt};
|
use js_int::{Int, UInt};
|
||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
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 serde_json::Value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{Event, EventType, RoomEvent, StateEvent, Void};
|
||||||
Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent, RoomEvent, StateEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Defines the power levels (privileges) of users in the room.
|
/// Defines the power levels (privileges) of users in the room.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@ -87,57 +85,39 @@ pub struct PowerLevelsEventContent {
|
|||||||
pub notifications: NotificationPowerLevels,
|
pub notifications: NotificationPowerLevels,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<PowerLevelsEvent> {
|
impl TryFrom<raw::PowerLevelsEvent> for PowerLevelsEvent {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Error = (raw::PowerLevelsEvent, Void);
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let raw: raw::PowerLevelsEvent = match serde_json::from_value(json.clone()) {
|
fn try_from(raw: raw::PowerLevelsEvent) -> Result<Self, Self::Error> {
|
||||||
Ok(raw) => raw,
|
Ok(Self {
|
||||||
Err(error) => {
|
content: crate::convert_content(raw.content),
|
||||||
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,
|
|
||||||
},
|
|
||||||
event_id: raw.event_id,
|
event_id: raw.event_id,
|
||||||
origin_server_ts: raw.origin_server_ts,
|
origin_server_ts: raw.origin_server_ts,
|
||||||
prev_content: raw.prev_content.map(|prev| PowerLevelsEventContent {
|
prev_content: raw.prev_content.map(crate::convert_content),
|
||||||
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,
|
|
||||||
}),
|
|
||||||
room_id: raw.room_id,
|
room_id: raw.room_id,
|
||||||
|
unsigned: raw.unsigned,
|
||||||
sender: raw.sender,
|
sender: raw.sender,
|
||||||
state_key: raw.state_key,
|
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!(
|
impl_state_event!(
|
||||||
PowerLevelsEvent,
|
PowerLevelsEvent,
|
||||||
PowerLevelsEventContent,
|
PowerLevelsEventContent,
|
||||||
EventType::RoomPowerLevels
|
EventType::RoomPowerLevels,
|
||||||
|
raw
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<PowerLevelsEventContent> {
|
pub(crate) mod raw {
|
||||||
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 {
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Defines the power levels (privileges) of users in the room.
|
/// Defines the power levels (privileges) of users in the room.
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
//! Types for the *m.room.server_acl* event.
|
//! Types for the *m.room.server_acl* event.
|
||||||
|
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use js_int::UInt;
|
use js_int::UInt;
|
||||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
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 serde_json::Value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{default_true, Event as _, EventType, RoomEvent, StateEvent, Void};
|
||||||
default_true, Event, EventResult, EventType, InnerInvalidEvent, InvalidEvent, RoomEvent,
|
|
||||||
StateEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// An event to indicate which servers are permitted to participate in the room.
|
/// An event to indicate which servers are permitted to participate in the room.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@ -68,43 +67,32 @@ pub struct ServerAclEventContent {
|
|||||||
pub deny: Vec<String>,
|
pub deny: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<ServerAclEvent> {
|
impl TryFrom<raw::ServerAclEvent> for ServerAclEvent {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Error = (raw::ServerAclEvent, Void);
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let json = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let raw: raw::ServerAclEvent = match serde_json::from_value(json.clone()) {
|
fn try_from(raw: raw::ServerAclEvent) -> Result<Self, Self::Error> {
|
||||||
Ok(raw) => raw,
|
Ok(Self {
|
||||||
Err(error) => {
|
content: crate::convert_content(raw.content),
|
||||||
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,
|
|
||||||
},
|
|
||||||
event_id: raw.event_id,
|
event_id: raw.event_id,
|
||||||
origin_server_ts: raw.origin_server_ts,
|
origin_server_ts: raw.origin_server_ts,
|
||||||
prev_content: raw.prev_content.map(|prev| ServerAclEventContent {
|
prev_content: raw.prev_content.map(crate::convert_content),
|
||||||
allow_ip_literals: prev.allow_ip_literals,
|
|
||||||
allow: prev.allow,
|
|
||||||
deny: prev.deny,
|
|
||||||
}),
|
|
||||||
room_id: raw.room_id,
|
room_id: raw.room_id,
|
||||||
unsigned: raw.unsigned,
|
|
||||||
sender: raw.sender,
|
sender: raw.sender,
|
||||||
state_key: raw.state_key,
|
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!(
|
impl_state_event!(
|
||||||
ServerAclEvent,
|
ServerAclEvent,
|
||||||
ServerAclEventContent,
|
ServerAclEventContent,
|
||||||
EventType::RoomServerAcl
|
EventType::RoomServerAcl,
|
||||||
|
raw
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<ServerAclEventContent> {
|
pub(crate) mod raw {
|
||||||
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 {
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// An event to indicate which servers are permitted to participate in the room.
|
/// An event to indicate which servers are permitted to participate in the room.
|
||||||
@ -221,12 +183,13 @@ mod raw {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::ServerAclEvent;
|
use super::ServerAclEvent;
|
||||||
|
use crate::EventResult;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn default_values() {
|
fn default_values() {
|
||||||
let server_acl_event: ServerAclEvent =
|
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"}"#
|
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"}"#)
|
||||||
.parse().unwrap();
|
.unwrap().into_result().unwrap();
|
||||||
|
|
||||||
assert_eq!(server_acl_event.content.allow_ip_literals, true);
|
assert_eq!(server_acl_event.content.allow_ip_literals, true);
|
||||||
assert!(server_acl_event.content.allow.is_empty());
|
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 std::convert::TryFrom;
|
||||||
|
|
||||||
use ruma_identifiers::UserId;
|
use ruma_identifiers::UserId;
|
||||||
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use serde_json::from_value;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
room::{
|
room::{
|
||||||
@ -20,7 +19,7 @@ use crate::{
|
|||||||
power_levels::PowerLevelsEventContent, third_party_invite::ThirdPartyInviteEventContent,
|
power_levels::PowerLevelsEventContent, third_party_invite::ThirdPartyInviteEventContent,
|
||||||
topic::TopicEventContent,
|
topic::TopicEventContent,
|
||||||
},
|
},
|
||||||
EventResult, EventType, InnerInvalidEvent, InvalidEvent,
|
EventResultCompatible, EventType,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A stripped-down version of a state event that is included along with some other events.
|
/// 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.
|
/// A stripped-down version of the *m.room.topic* event.
|
||||||
pub type StrippedRoomTopic = StrippedStateContent<TopicEventContent>;
|
pub type StrippedRoomTopic = StrippedStateContent<TopicEventContent>;
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for EventResult<StrippedState> {
|
impl EventResultCompatible for StrippedState {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
type Raw = raw::StrippedState;
|
||||||
where
|
}
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let value = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
let event_type_value = match value.get("type") {
|
impl TryFrom<raw::StrippedState> for StrippedState {
|
||||||
Some(value) => value.clone(),
|
type Error = (raw::StrippedState, String);
|
||||||
None => {
|
|
||||||
return Ok(EventResult::Err(InvalidEvent(InnerInvalidEvent::Validation {
|
|
||||||
json: value,
|
|
||||||
message: "missing field `type`".to_string(),
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let event_type = match from_value::<EventType>(event_type_value.clone()) {
|
fn try_from(raw: raw::StrippedState) -> Result<Self, Self::Error> {
|
||||||
Ok(event_type) => event_type,
|
unimplemented!()
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*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 {
|
impl Serialize for StrippedState {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
@ -327,109 +175,106 @@ impl Serialize for StrippedState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl<'de, C> Deserialize<'de> for EventResult<StrippedStateContent<C>>
|
mod raw {
|
||||||
// where
|
use serde::{Deserialize, Deserializer};
|
||||||
// EventResult<C>: Deserialize<'de>,
|
|
||||||
// {
|
|
||||||
// fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
// where
|
|
||||||
// D: Deserializer<'de>,
|
|
||||||
// {
|
|
||||||
// let value = serde_json::Value::deserialize(deserializer)?;
|
|
||||||
|
|
||||||
// let event_type_value = match value.get("type") {
|
use super::StrippedStateContent;
|
||||||
// Some(value) => value.clone(),
|
use crate::room::{
|
||||||
// None => {
|
aliases::raw::AliasesEventContent, avatar::raw::AvatarEventContent,
|
||||||
// return Ok(EventResult::validation_error("missing field `type`".to_string(), value))
|
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()) {
|
/// A stripped-down version of the *m.room.aliases* event.
|
||||||
// Ok(event_type) => event_type,
|
pub type StrippedRoomAliases = StrippedStateContent<AliasesEventContent>;
|
||||||
// Err(error) => {
|
|
||||||
// return Ok(EventResult::validation_error(error.to_string(), value))
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// let content = match value.get("content") {
|
/// A stripped-down version of the *m.room.avatar* event.
|
||||||
// Some(content_value) => match content_value.as_object() {
|
pub type StrippedRoomAvatar = StrippedStateContent<AvatarEventContent>;
|
||||||
// Some(content) => content,
|
|
||||||
// None => {
|
|
||||||
// return Ok(EventResult::validation_error("field `content` must be an object".to_string(), value))
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// None => {
|
|
||||||
// return Ok(EventResult::validation_error("missing field `content`".to_string(), value))
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// match event_type {
|
/// A stripped-down version of the *m.room.canonical_alias* event.
|
||||||
// EventType::RoomAliases => stripped_state_content::<AliasesEventContent>(event_type, value),
|
pub type StrippedRoomCanonicalAlias = StrippedStateContent<CanonicalAliasEventContent>;
|
||||||
// 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)),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /// Reduces the boilerplate in the match arms of `impl Deserialize for StrippedState`.
|
/// A stripped-down version of the *m.room.create* event.
|
||||||
// #[inline]
|
pub type StrippedRoomCreate = StrippedStateContent<CreateEventContent>;
|
||||||
// fn create_stripped_state(
|
|
||||||
// event_type: EventType,
|
|
||||||
// value: Value,
|
|
||||||
// ) -> Result<EventResult<StrippedState>, serde_json::Error>
|
|
||||||
// where
|
|
||||||
// for<'de> EventResult<C>: Deserialize<'de>,
|
|
||||||
// {
|
|
||||||
// let event_result = from_value::<EventResult<C>>(value)?;
|
|
||||||
|
|
||||||
// Ok(EventResult::Ok(StrippedStateContent {
|
/// A stripped-down version of the *m.room.guest_access* event.
|
||||||
// content: event_result.into_result().unwrap(),
|
pub type StrippedRoomGuestAccess = StrippedStateContent<GuestAccessEventContent>;
|
||||||
// event_type,
|
|
||||||
// state_key: match value.get("state_key") {
|
/// A stripped-down version of the *m.room.history_visibility* event.
|
||||||
// Some(state_key_value) => match state_key_value.as_str() {
|
pub type StrippedRoomHistoryVisibility = StrippedStateContent<HistoryVisibilityEventContent>;
|
||||||
// Some(state_key) => state_key.to_string(),
|
|
||||||
// None => {
|
/// A stripped-down version of the *m.room.join_rules* event.
|
||||||
// return Ok(EventResult::validation_error("field `state_key` must be a string".to_string(), value));
|
pub type StrippedRoomJoinRules = StrippedStateContent<JoinRulesEventContent>;
|
||||||
// }
|
|
||||||
// },
|
/// A stripped-down version of the *m.room.member* event.
|
||||||
// None => {
|
pub type StrippedRoomMember = StrippedStateContent<MemberEventContent>;
|
||||||
// return Ok(EventResult::validation_error("missing field `state_key`".to_string(), value));
|
|
||||||
// }
|
/// A stripped-down version of the *m.room.name* event.
|
||||||
// },
|
pub type StrippedRoomName = StrippedStateContent<NameEventContent>;
|
||||||
// sender: match value.get("sender") {
|
|
||||||
// Some(sender_value) => match sender_value.as_str() {
|
/// A stripped-down version of the *m.room.power_levels* event.
|
||||||
// Some(sender_str) => match UserId::try_from(sender_str) {
|
pub type StrippedRoomPowerLevels = StrippedStateContent<PowerLevelsEventContent>;
|
||||||
// Ok(sender) => sender,
|
|
||||||
// Err(error) => {
|
/// A stripped-down version of the *m.room.third_party_invite* event.
|
||||||
// return Ok(EventResult::validation_error(error.to_string(), value));
|
pub type StrippedRoomThirdPartyInvite = StrippedStateContent<ThirdPartyInviteEventContent>;
|
||||||
// }
|
|
||||||
// },
|
/// A stripped-down version of the *m.room.topic* event.
|
||||||
// None => {
|
pub type StrippedRoomTopic = StrippedStateContent<TopicEventContent>;
|
||||||
// return Ok(EventResult::validation_error("field `sender` must be a string".to_string(), value));
|
|
||||||
// }
|
/// A stripped-down version of a state event that is included along with some other events.
|
||||||
// },
|
#[derive(Clone, Debug)]
|
||||||
// None => {
|
#[allow(clippy::large_enum_variant)]
|
||||||
// return Ok(EventResult::validation_error("missing field `sender`".to_string(), value));
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@ -442,7 +287,7 @@ mod tests {
|
|||||||
use super::{StrippedRoomName, StrippedRoomTopic, StrippedState};
|
use super::{StrippedRoomName, StrippedRoomTopic, StrippedState};
|
||||||
use crate::{
|
use crate::{
|
||||||
room::{join_rules::JoinRule, topic::TopicEventContent},
|
room::{join_rules::JoinRule, topic::TopicEventContent},
|
||||||
EventType,
|
EventResult, EventType,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[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) => {
|
StrippedState::RoomName(event) => {
|
||||||
assert_eq!(event.content.name, Some("Ruma".to_string()));
|
assert_eq!(event.content.name, Some("Ruma".to_string()));
|
||||||
assert_eq!(event.event_type, EventType::RoomName);
|
assert_eq!(event.event_type, EventType::RoomName);
|
||||||
@ -520,9 +369,18 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Ensure `StrippedStateContent` can be parsed, not just `StrippedState`.
|
// 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) => {
|
StrippedState::RoomJoinRules(event) => {
|
||||||
assert_eq!(event.content.join_rule, JoinRule::Public);
|
assert_eq!(event.content.join_rule, JoinRule::Public);
|
||||||
assert_eq!(event.event_type, EventType::RoomJoinRules);
|
assert_eq!(event.event_type, EventType::RoomJoinRules);
|
||||||
@ -532,7 +390,11 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match avatar_event.parse().unwrap() {
|
match serde_json::from_str::<EventResult<_>>(avatar_event)
|
||||||
|
.unwrap()
|
||||||
|
.into_result()
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
StrippedState::RoomAvatar(event) => {
|
StrippedState::RoomAvatar(event) => {
|
||||||
let image_info = event.content.info.unwrap();
|
let image_info = event.content.info.unwrap();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user