Any event enum macro implementation (also generates event content enums)
This commit is contained in:
parent
b0d775a535
commit
c2b1c9897b
263
ruma-events-macros/src/event_enum.rs
Normal file
263
ruma-events-macros/src/event_enum.rs
Normal file
@ -0,0 +1,263 @@
|
||||
//! Implementation of event enum and event content enum macros.
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
parse::{self, Parse, ParseStream},
|
||||
Attribute, Expr, ExprLit, Ident, Lit, LitStr, Token,
|
||||
};
|
||||
|
||||
/// Create a content enum from `EventEnumInput`.
|
||||
pub fn expand_event_enum(input: EventEnumInput) -> syn::Result<TokenStream> {
|
||||
let attrs = &input.attrs;
|
||||
let ident = &input.name;
|
||||
let event_type_str = &input.events;
|
||||
|
||||
let variants = input.events.iter().map(to_camel_case).collect::<Vec<_>>();
|
||||
let content = input.events.iter().map(to_event_path).collect::<Vec<_>>();
|
||||
|
||||
let event_enum = quote! {
|
||||
#( #attrs )*
|
||||
#[derive(Clone, Debug, ::serde::Serialize)]
|
||||
#[serde(untagged)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum #ident {
|
||||
#(
|
||||
#[doc = #event_type_str]
|
||||
#variants(#content)
|
||||
),*
|
||||
}
|
||||
};
|
||||
|
||||
let event_deserialize_impl = quote! {
|
||||
impl<'de> ::serde::de::Deserialize<'de> for #ident {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: ::serde::de::Deserializer<'de>,
|
||||
{
|
||||
use ::serde::de::Error as _;
|
||||
|
||||
let json = ::serde_json::Value::deserialize(deserializer)?;
|
||||
let ev_type: String = ::ruma_events::util::get_field(&json, "type")?;
|
||||
match ev_type.as_str() {
|
||||
#(
|
||||
#event_type_str => {
|
||||
let event = ::serde_json::from_value::<#content>(json).map_err(D::Error::custom)?;
|
||||
Ok(#ident::#variants(event))
|
||||
},
|
||||
)*
|
||||
_ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type)))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let event_content_enum = expand_content_enum(input)?;
|
||||
|
||||
Ok(quote! {
|
||||
#event_enum
|
||||
|
||||
#event_deserialize_impl
|
||||
|
||||
#event_content_enum
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a content enum from `EventEnumInput`.
|
||||
pub fn expand_content_enum(input: EventEnumInput) -> syn::Result<TokenStream> {
|
||||
let attrs = &input.attrs;
|
||||
let ident = Ident::new(
|
||||
&format!("{}Content", input.name.to_string()),
|
||||
input.name.span(),
|
||||
);
|
||||
let event_type_str = &input.events;
|
||||
|
||||
let variants = input.events.iter().map(to_camel_case).collect::<Vec<_>>();
|
||||
let content = input
|
||||
.events
|
||||
.iter()
|
||||
.map(to_event_content_path)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let content_enum = quote! {
|
||||
#( #attrs )*
|
||||
#[derive(Clone, Debug, ::serde::Serialize)]
|
||||
#[serde(untagged)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum #ident {
|
||||
#(
|
||||
#[doc = #event_type_str]
|
||||
#variants(#content)
|
||||
),*
|
||||
}
|
||||
};
|
||||
|
||||
let event_content_impl = quote! {
|
||||
impl ::ruma_events::EventContent for #ident {
|
||||
fn event_type(&self) -> &str {
|
||||
match self {
|
||||
#( Self::#variants(content) => content.event_type() ),*
|
||||
}
|
||||
}
|
||||
|
||||
fn from_parts(event_type: &str, input: Box<::serde_json::value::RawValue>) -> Result<Self, String> {
|
||||
match event_type {
|
||||
#(
|
||||
#event_type_str => {
|
||||
let content = #content::from_parts(event_type, input)?;
|
||||
Ok(#ident::#variants(content))
|
||||
},
|
||||
)*
|
||||
ev => Err(format!("event not supported {}", ev)),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let marker_trait_impls = marker_traits(&ident);
|
||||
|
||||
Ok(quote! {
|
||||
#content_enum
|
||||
|
||||
#event_content_impl
|
||||
|
||||
#marker_trait_impls
|
||||
})
|
||||
}
|
||||
|
||||
fn marker_traits(ident: &Ident) -> TokenStream {
|
||||
match ident.to_string().as_str() {
|
||||
"AnyStateEventContent" => quote! {
|
||||
impl ::ruma_events::RoomEventContent for #ident {}
|
||||
impl ::ruma_events::StateEventContent for #ident {}
|
||||
},
|
||||
"AnyMessageEventContent" => quote! {
|
||||
impl ::ruma_events::RoomEventContent for #ident {}
|
||||
impl ::ruma_events::MessageEventContent for #ident {}
|
||||
},
|
||||
"AnyEphemeralRoomEventContent" => quote! {
|
||||
impl ::ruma_events::EphemeralRoomEventContent for #ident {}
|
||||
},
|
||||
"AnyBasicEventContent" => quote! {
|
||||
impl ::ruma_events::BasicEventContent for #ident {}
|
||||
},
|
||||
_ => TokenStream::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_event_path(name: &LitStr) -> TokenStream {
|
||||
let span = name.span();
|
||||
let name = name.value();
|
||||
|
||||
assert_eq!(&name[..2], "m.");
|
||||
|
||||
let path = name[2..].split('.').collect::<Vec<_>>();
|
||||
|
||||
let event_str = path.last().unwrap();
|
||||
let event = event_str
|
||||
.split('_')
|
||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
||||
.collect::<String>();
|
||||
|
||||
let content_str = Ident::new(&format!("{}Event", event), span);
|
||||
let path = path.iter().map(|s| Ident::new(s, span));
|
||||
quote! {
|
||||
::ruma_events::#( #path )::*::#content_str
|
||||
}
|
||||
}
|
||||
|
||||
fn to_event_content_path(name: &LitStr) -> TokenStream {
|
||||
let span = name.span();
|
||||
let name = name.value();
|
||||
|
||||
assert_eq!(&name[..2], "m.");
|
||||
|
||||
let path = name[2..].split('.').collect::<Vec<_>>();
|
||||
|
||||
let event_str = path.last().unwrap();
|
||||
let event = event_str
|
||||
.split('_')
|
||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
||||
.collect::<String>();
|
||||
|
||||
let content_str = Ident::new(&format!("{}EventContent", event), span);
|
||||
let path = path.iter().map(|s| Ident::new(s, span));
|
||||
quote! {
|
||||
::ruma_events::#( #path )::*::#content_str
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits the given `event_type` string on `.` and `_` removing the `m.room.` then
|
||||
/// camel casing to give the `Event` struct name.
|
||||
pub(crate) fn to_camel_case(name: &LitStr) -> Ident {
|
||||
let span = name.span();
|
||||
let name = name.value();
|
||||
assert_eq!(&name[..2], "m.");
|
||||
let s = name[2..]
|
||||
.split(&['.', '_'] as &[char])
|
||||
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
|
||||
.collect::<String>();
|
||||
Ident::new(&s, span)
|
||||
}
|
||||
|
||||
/// Custom keywords for the `event_enum!` macro
|
||||
mod kw {
|
||||
syn::custom_keyword!(name);
|
||||
syn::custom_keyword!(events);
|
||||
}
|
||||
|
||||
/// The entire `event_enum!` macro structure directly as it appears in the source code.
|
||||
pub struct EventEnumInput {
|
||||
/// Outer attributes on the field, such as a docstring.
|
||||
pub attrs: Vec<Attribute>,
|
||||
|
||||
/// The name of the event.
|
||||
pub name: Ident,
|
||||
|
||||
/// An array of valid matrix event types. This will generate the variants of the event content type "name".
|
||||
/// There needs to be a corresponding variant in `ruma_events::EventType` for
|
||||
/// this event (converted to a valid Rust-style type name by stripping `m.`, replacing the
|
||||
/// remaining dots by underscores and then converting from snake_case to CamelCase).
|
||||
pub events: Vec<LitStr>,
|
||||
}
|
||||
|
||||
impl Parse for EventEnumInput {
|
||||
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
|
||||
let attrs = input.call(Attribute::parse_outer)?;
|
||||
// name field
|
||||
input.parse::<kw::name>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
// the name of our event enum
|
||||
let name: Ident = input.parse()?;
|
||||
input.parse::<Token![,]>()?;
|
||||
|
||||
// events field
|
||||
input.parse::<kw::events>()?;
|
||||
input.parse::<Token![:]>()?;
|
||||
|
||||
// an array of event names `["m.room.whatever"]`
|
||||
let ev_array = input.parse::<syn::ExprArray>()?;
|
||||
let events = ev_array
|
||||
.elems
|
||||
.into_iter()
|
||||
.map(|item| {
|
||||
if let Expr::Lit(ExprLit {
|
||||
lit: Lit::Str(lit_str),
|
||||
..
|
||||
}) = item
|
||||
{
|
||||
Ok(lit_str)
|
||||
} else {
|
||||
let msg = "values of field `events` are required to be a string literal";
|
||||
Err(syn::Error::new_spanned(item, msg))
|
||||
}
|
||||
})
|
||||
.collect::<syn::Result<_>>()?;
|
||||
|
||||
Ok(Self {
|
||||
attrs,
|
||||
name,
|
||||
events,
|
||||
})
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ use self::{
|
||||
expand_basic_event_content, expand_ephemeral_room_event_content, expand_event_content,
|
||||
expand_message_event_content, expand_room_event_content, expand_state_event_content,
|
||||
},
|
||||
event_enum::{expand_event_enum, EventEnumInput},
|
||||
gen::RumaEvent,
|
||||
parse::RumaEventInput,
|
||||
};
|
||||
@ -28,6 +29,7 @@ use self::{
|
||||
mod content_enum;
|
||||
mod event;
|
||||
mod event_content;
|
||||
mod event_enum;
|
||||
mod gen;
|
||||
mod parse;
|
||||
|
||||
@ -124,6 +126,19 @@ pub fn ruma_event(input: TokenStream) -> TokenStream {
|
||||
ruma_event.into_token_stream().into()
|
||||
}
|
||||
|
||||
/// Generates an enum to represent the various Matrix event types.
|
||||
///
|
||||
/// This macro also implements the necessary traits for the type to serialize and deserialize
|
||||
/// itself.
|
||||
// TODO more docs/example
|
||||
#[proc_macro]
|
||||
pub fn event_enum(input: TokenStream) -> TokenStream {
|
||||
let event_enum_input = syn::parse_macro_input!(input as EventEnumInput);
|
||||
expand_event_enum(event_enum_input)
|
||||
.unwrap_or_else(|err| err.to_compile_error())
|
||||
.into()
|
||||
}
|
||||
|
||||
/// Generates a content enum to represent the various Matrix event types.
|
||||
///
|
||||
/// This macro also implements the necessary traits for the type to serialize and deserialize
|
||||
|
@ -4,8 +4,13 @@ use js_int::UInt;
|
||||
use ruma_events_macros::MessageEventContent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::MessageEvent;
|
||||
|
||||
/// This event is sent by callers after sending an invite and by the callee after answering. Its
|
||||
/// purpose is to give the other party additional ICE candidates to try using to communicate.
|
||||
pub type CandidatesEvent = MessageEvent<CandidatesEventContent>;
|
||||
|
||||
/// The payload for `CandidatesEvent`.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)]
|
||||
#[ruma_event(type = "m.call.candidates")]
|
||||
pub struct CandidatesEventContent {
|
||||
|
@ -5,8 +5,13 @@ use ruma_events_macros::MessageEventContent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::{Display, EnumString};
|
||||
|
||||
use crate::MessageEvent;
|
||||
|
||||
/// Sent by either party to signal their termination of the call. This can be sent either once the
|
||||
/// call has has been established or before to abort the call.
|
||||
pub type HangupEvent = MessageEvent<HangupEventContent>;
|
||||
|
||||
/// The payload for `HangupEvent`.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)]
|
||||
#[ruma_event(type = "m.call.hangup")]
|
||||
pub struct HangupEventContent {
|
||||
|
@ -5,8 +5,12 @@ use ruma_events_macros::MessageEventContent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::SessionDescription;
|
||||
use crate::MessageEvent;
|
||||
|
||||
/// This event is sent by the caller when they wish to establish a call.
|
||||
pub type InviteEvent = MessageEvent<InviteEventContent>;
|
||||
|
||||
/// The payload for `InviteEvent`.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)]
|
||||
#[ruma_event(type = "m.call.invite")]
|
||||
pub struct InviteEventContent {
|
||||
|
@ -1,74 +0,0 @@
|
||||
use ruma_events_macros::event_content_enum;
|
||||
|
||||
event_content_enum! {
|
||||
/// Any basic event's content.
|
||||
name: AnyBasicEventContent,
|
||||
events: [
|
||||
"m.direct",
|
||||
"m.dummy",
|
||||
"m.ignored_user_list",
|
||||
"m.push_rules",
|
||||
"m.room_key",
|
||||
]
|
||||
}
|
||||
|
||||
event_content_enum! {
|
||||
/// Any ephemeral room event.
|
||||
name: AnyEphemeralRoomEventContent,
|
||||
events: [ "m.typing", "m.receipt" ]
|
||||
}
|
||||
|
||||
event_content_enum! {
|
||||
/// Any message event's content.
|
||||
name: AnyMessageEventContent,
|
||||
events: [
|
||||
"m.call.answer",
|
||||
"m.call.invite",
|
||||
"m.call.hangup",
|
||||
"m.call.candidates",
|
||||
"m.room.message",
|
||||
"m.room.message.feedback",
|
||||
"m.sticker",
|
||||
]
|
||||
}
|
||||
|
||||
event_content_enum! {
|
||||
/// Any state event's content.
|
||||
name: AnyStateEventContent,
|
||||
events: [
|
||||
"m.room.aliases",
|
||||
"m.room.avatar",
|
||||
"m.room.canonical_alias",
|
||||
"m.room.create",
|
||||
"m.room.encryption",
|
||||
"m.room.guest_access",
|
||||
"m.room.history_visibility",
|
||||
"m.room.join_rules",
|
||||
"m.room.member",
|
||||
"m.room.name",
|
||||
"m.room.pinned_events",
|
||||
"m.room.power_levels",
|
||||
"m.room.server_acl",
|
||||
"m.room.third_party_invite",
|
||||
"m.room.tombstone",
|
||||
"m.room.topic",
|
||||
]
|
||||
}
|
||||
|
||||
event_content_enum! {
|
||||
/// Any to-device event's content.
|
||||
name: AnyToDeviceEventContent,
|
||||
events: [
|
||||
"m.dummy",
|
||||
"m.room_key",
|
||||
//"m.room_key_request",
|
||||
//"m.forwarded_room_key",
|
||||
//"m.key.verification.request",
|
||||
"m.key.verification.start",
|
||||
//"m.key.verification.cancel",
|
||||
//"m.key.verification.accept",
|
||||
//"m.key.verification.key",
|
||||
//"m.key.verification.mac",
|
||||
//"m.room.encrypted",
|
||||
]
|
||||
}
|
74
src/enums.rs
Normal file
74
src/enums.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use ruma_events_macros::event_enum;
|
||||
|
||||
event_enum! {
|
||||
/// Any basic event.
|
||||
name: AnyBasicEvent,
|
||||
events: [
|
||||
"m.direct",
|
||||
"m.dummy",
|
||||
"m.ignored_user_list",
|
||||
"m.push_rules",
|
||||
"m.room_key",
|
||||
]
|
||||
}
|
||||
|
||||
event_enum! {
|
||||
/// Any ephemeral room event.
|
||||
name: AnyEphemeralRoomEvent,
|
||||
events: [ "m.typing", "m.receipt" ]
|
||||
}
|
||||
|
||||
event_enum! {
|
||||
/// Any message event.
|
||||
name: AnyMessageEvent,
|
||||
events: [
|
||||
"m.call.answer",
|
||||
"m.call.invite",
|
||||
"m.call.hangup",
|
||||
"m.call.candidates",
|
||||
"m.room.message",
|
||||
"m.room.message.feedback",
|
||||
"m.sticker",
|
||||
]
|
||||
}
|
||||
|
||||
event_enum! {
|
||||
/// Any state event.
|
||||
name: AnyStateEvent,
|
||||
events: [
|
||||
"m.room.aliases",
|
||||
"m.room.avatar",
|
||||
// "m.room.canonical_alias",
|
||||
// "m.room.create",
|
||||
// "m.room.encryption",
|
||||
// "m.room.guest_access",
|
||||
// "m.room.history_visibility",
|
||||
// "m.room.join_rules",
|
||||
// "m.room.member",
|
||||
// "m.room.name",
|
||||
// "m.room.pinned_events",
|
||||
// "m.room.power_levels",
|
||||
// "m.room.server_acl",
|
||||
// "m.room.third_party_invite",
|
||||
// "m.room.tombstone",
|
||||
// "m.room.topic",
|
||||
]
|
||||
}
|
||||
|
||||
event_enum! {
|
||||
/// Any to-device event.
|
||||
name: AnyToDeviceEvent,
|
||||
events: [
|
||||
"m.dummy",
|
||||
"m.room_key",
|
||||
//"m.room_key_request",
|
||||
//"m.forwarded_room_key",
|
||||
//"m.key.verification.request",
|
||||
"m.key.verification.start",
|
||||
//"m.key.verification.cancel",
|
||||
//"m.key.verification.accept",
|
||||
//"m.key.verification.key",
|
||||
//"m.key.verification.mac",
|
||||
//"m.room.encrypted",
|
||||
]
|
||||
}
|
@ -4,7 +4,12 @@ use ruma_events_macros::BasicEventContent;
|
||||
use ruma_identifiers::UserId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::BasicEvent;
|
||||
|
||||
/// A list of users to ignore.
|
||||
pub type IgnoredUserListEvent = BasicEvent<IgnoredUserListEventContent>;
|
||||
|
||||
/// The payload for `IgnoredUserListEvent`.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, BasicEventContent)]
|
||||
#[ruma_event(type = "m.ignored_user_list")]
|
||||
pub struct IgnoredUserListEventContent {
|
||||
|
11
src/lib.rs
11
src/lib.rs
@ -128,7 +128,7 @@ use self::room::redaction::RedactionEvent;
|
||||
pub use ruma_serde::empty::Empty;
|
||||
|
||||
mod algorithm;
|
||||
mod content_enums;
|
||||
mod enums;
|
||||
mod error;
|
||||
mod event_kinds;
|
||||
mod event_type;
|
||||
@ -160,11 +160,12 @@ pub mod typing;
|
||||
|
||||
pub use self::{
|
||||
algorithm::Algorithm,
|
||||
content_enums::{
|
||||
AnyBasicEventContent, AnyEphemeralRoomEventContent, AnyMessageEventContent,
|
||||
AnyStateEventContent, AnyToDeviceEventContent,
|
||||
},
|
||||
custom::{CustomBasicEvent, CustomMessageEvent, CustomStateEvent},
|
||||
enums::{
|
||||
AnyBasicEvent, AnyBasicEventContent, AnyEphemeralRoomEvent, AnyEphemeralRoomEventContent,
|
||||
AnyMessageEvent, AnyMessageEventContent, AnyStateEvent, AnyStateEventContent,
|
||||
AnyToDeviceEvent, AnyToDeviceEventContent,
|
||||
},
|
||||
error::{FromStrError, InvalidEvent, InvalidInput},
|
||||
event_kinds::{
|
||||
BasicEvent, EphemeralRoomEvent, MessageEvent, MessageEventStub, StateEvent, StateEventStub,
|
||||
|
@ -4,7 +4,12 @@ use ruma_events_macros::StateEventContent;
|
||||
use ruma_identifiers::RoomAliasId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::StateEvent;
|
||||
|
||||
/// Informs the room about what room aliases it has been given.
|
||||
pub type AliasesEvent = StateEvent<AliasesEventContent>;
|
||||
|
||||
/// The payload for `AliasesEvent`.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, StateEventContent)]
|
||||
#[ruma_event(type = "m.room.aliases")]
|
||||
pub struct AliasesEventContent {
|
||||
|
@ -4,10 +4,14 @@ use ruma_events_macros::StateEventContent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::ImageInfo;
|
||||
use crate::StateEvent;
|
||||
|
||||
/// A picture that is associated with the room.
|
||||
///
|
||||
/// This can be displayed alongside the room information.
|
||||
pub type AvatarEvent = StateEvent<AvatarEventContent>;
|
||||
|
||||
/// The payload for `AvatarEvent`.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, StateEventContent)]
|
||||
#[ruma_event(type = "m.room.avatar")]
|
||||
pub struct AvatarEventContent {
|
||||
|
@ -9,6 +9,13 @@ use super::{EncryptedFile, ImageInfo, ThumbnailInfo};
|
||||
|
||||
pub mod feedback;
|
||||
|
||||
use crate::MessageEvent as OuterMessageEvent;
|
||||
|
||||
/// This event is used when sending messages in a room.
|
||||
///
|
||||
/// Messages are not limited to be text.
|
||||
pub type MessageEvent = OuterMessageEvent<MessageEventContent>;
|
||||
|
||||
/// The payload for `MessageEvent`.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)]
|
||||
#[ruma_event(type = "m.room.message")]
|
||||
|
@ -5,10 +5,15 @@ use ruma_identifiers::EventId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::{Display, EnumString};
|
||||
|
||||
use crate::MessageEvent;
|
||||
|
||||
/// An acknowledgement of a message.
|
||||
///
|
||||
/// N.B.: Usage of this event is discouraged in favor of the receipts module. Most clients will
|
||||
/// not recognize this event.
|
||||
pub type FeedbackEvent = MessageEvent<FeedbackEventContent>;
|
||||
|
||||
/// The payload for `FeedbackEvent`.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)]
|
||||
#[ruma_event(type = "m.room.message.feedback")]
|
||||
pub struct FeedbackEventContent {
|
||||
|
117
tests/event_enums.rs
Normal file
117
tests/event_enums.rs
Normal file
@ -0,0 +1,117 @@
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
time::{Duration, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use js_int::UInt;
|
||||
use matches::assert_matches;
|
||||
use ruma_identifiers::{EventId, RoomId, UserId};
|
||||
use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
|
||||
|
||||
use ruma_events::{
|
||||
call::{answer::AnswerEventContent, SessionDescription, SessionDescriptionType},
|
||||
room::{ImageInfo, ThumbnailInfo},
|
||||
sticker::StickerEventContent,
|
||||
AnyMessageEvent, MessageEvent, UnsignedData,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn deserialize_message_event() {
|
||||
let json_data = json!({
|
||||
"content": {
|
||||
"answer": {
|
||||
"type": "answer",
|
||||
"sdp": "Hello"
|
||||
},
|
||||
"call_id": "foofoo",
|
||||
"version": 1
|
||||
},
|
||||
"event_id": "$h29iv0s8:example.com",
|
||||
"origin_server_ts": 1,
|
||||
"room_id": "!roomid:room.com",
|
||||
"sender": "@carl:example.com",
|
||||
"type": "m.call.answer"
|
||||
});
|
||||
|
||||
assert_matches!(
|
||||
from_json_value::<AnyMessageEvent>(json_data)
|
||||
.unwrap(),
|
||||
AnyMessageEvent::CallAnswer(MessageEvent {
|
||||
content: AnswerEventContent {
|
||||
answer: SessionDescription {
|
||||
session_type: SessionDescriptionType::Answer,
|
||||
sdp,
|
||||
},
|
||||
call_id,
|
||||
version,
|
||||
},
|
||||
event_id,
|
||||
origin_server_ts,
|
||||
room_id,
|
||||
sender,
|
||||
unsigned,
|
||||
}) if sdp == "Hello" && call_id == "foofoo" && version == UInt::new(1).unwrap()
|
||||
&& event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
|
||||
&& origin_server_ts == UNIX_EPOCH + Duration::from_millis(1)
|
||||
&& room_id == RoomId::try_from("!roomid:room.com").unwrap()
|
||||
&& sender == UserId::try_from("@carl:example.com").unwrap()
|
||||
&& unsigned.is_empty()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_message_event() {
|
||||
let aliases_event = AnyMessageEvent::Sticker(MessageEvent {
|
||||
content: StickerEventContent {
|
||||
body: "Hello".into(),
|
||||
info: ImageInfo {
|
||||
height: UInt::new(423),
|
||||
width: UInt::new(1011),
|
||||
mimetype: Some("image/png".into()),
|
||||
size: UInt::new(84242),
|
||||
thumbnail_info: Some(Box::new(ThumbnailInfo {
|
||||
width: UInt::new(800),
|
||||
height: UInt::new(334),
|
||||
mimetype: Some("image/png".into()),
|
||||
size: UInt::new(82595),
|
||||
})),
|
||||
thumbnail_url: Some("mxc://matrix.org".into()),
|
||||
thumbnail_file: None,
|
||||
},
|
||||
url: "http://www.matrix.org".into(),
|
||||
},
|
||||
event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
|
||||
origin_server_ts: UNIX_EPOCH + Duration::from_millis(1),
|
||||
room_id: RoomId::try_from("!roomid:room.com").unwrap(),
|
||||
sender: UserId::try_from("@carl:example.com").unwrap(),
|
||||
unsigned: UnsignedData::default(),
|
||||
});
|
||||
|
||||
let actual = to_json_value(&aliases_event).unwrap();
|
||||
let expected = json!({
|
||||
"content": {
|
||||
"body": "Hello",
|
||||
"info": {
|
||||
"h": 423,
|
||||
"mimetype": "image/png",
|
||||
"size": 84242,
|
||||
"thumbnail_info": {
|
||||
"h": 334,
|
||||
"mimetype": "image/png",
|
||||
"size": 82595,
|
||||
"w": 800
|
||||
},
|
||||
"thumbnail_url": "mxc://matrix.org",
|
||||
"w": 1011
|
||||
},
|
||||
"url": "http://www.matrix.org"
|
||||
},
|
||||
"event_id": "$h29iv0s8:example.com",
|
||||
"origin_server_ts": 1,
|
||||
"room_id": "!roomid:room.com",
|
||||
"sender": "@carl:example.com",
|
||||
"type": "m.sticker",
|
||||
});
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user