events: Declare all event enums inside one macro invocation

This commit is contained in:
Devin Ragotzy 2021-05-14 19:52:34 -04:00 committed by GitHub
parent a4811663de
commit d1f5fb1d87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 354 additions and 389 deletions

View File

@ -4,7 +4,7 @@ use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote, ToTokens};
use syn::{Attribute, Ident, LitStr};
use crate::event_parse::{EventEnumEntry, EventEnumInput, EventKind, EventKindVariation};
use crate::event_parse::{EventEnumDecl, EventEnumEntry, EventKind, EventKindVariation};
fn is_non_stripped_room_event(kind: &EventKind, var: &EventKindVariation) -> bool {
matches!(kind, EventKind::Message | EventKind::State)
@ -43,7 +43,7 @@ const EVENT_FIELDS: &[(&str, EventKindFn)] = &[
];
/// Create a content enum from `EventEnumInput`.
pub fn expand_event_enum(input: EventEnumInput) -> syn::Result<TokenStream> {
pub fn expand_event_enum(input: &EventEnumDecl) -> syn::Result<TokenStream> {
let ruma_events = crate::import_ruma_events();
let name = &input.name;
@ -969,13 +969,13 @@ fn field_return_type(
}
}
struct EventEnumVariant {
pub(crate) struct EventEnumVariant {
pub attrs: Vec<Attribute>,
pub ident: Ident,
}
impl EventEnumVariant {
fn to_tokens<T>(&self, prefix: Option<T>, with_attrs: bool) -> TokenStream
pub(crate) fn to_tokens<T>(&self, prefix: Option<T>, with_attrs: bool) -> TokenStream
where
T: ToTokens,
{
@ -993,21 +993,21 @@ impl EventEnumVariant {
tokens
}
fn decl(&self) -> TokenStream {
pub(crate) fn decl(&self) -> TokenStream {
self.to_tokens::<TokenStream>(None, true)
}
fn match_arm(&self, prefix: impl ToTokens) -> TokenStream {
pub(crate) fn match_arm(&self, prefix: impl ToTokens) -> TokenStream {
self.to_tokens(Some(prefix), true)
}
fn ctor(&self, prefix: impl ToTokens) -> TokenStream {
pub(crate) fn ctor(&self, prefix: impl ToTokens) -> TokenStream {
self.to_tokens(Some(prefix), false)
}
}
impl EventEnumEntry {
fn to_variant(&self) -> syn::Result<EventEnumVariant> {
pub(crate) fn to_variant(&self) -> syn::Result<EventEnumVariant> {
let attrs = self.attrs.clone();
let ident = to_camel_case(&self.ev_type)?;
Ok(EventEnumVariant { attrs, ident })

View File

@ -5,7 +5,7 @@ use std::fmt;
use proc_macro2::Span;
use quote::format_ident;
use syn::{
bracketed,
braced,
parse::{self, Parse, ParseStream},
Attribute, Ident, LitStr, Token,
};
@ -140,8 +140,8 @@ impl Parse for EventKind {
"State" => EventKind::State,
"ToDevice" => EventKind::ToDevice,
id => {
return Err(syn::Error::new(
input.span(),
return Err(syn::Error::new_spanned(
ident,
format!(
"valid event kinds are GlobalAccountData, RoomAccountData, EphemeralRoom, \
Message, State, ToDevice found `{}`",
@ -184,48 +184,6 @@ pub fn to_kind_variation(ident: &Ident) -> Option<(EventKind, EventKindVariation
}
}
/// 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: EventKind,
/// An array of valid matrix event types.
///
/// This will generate the variants of the event 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<EventEnumEntry>,
}
impl Parse for EventEnumInput {
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
// "name" field
let _: kw::kind = input.parse()?;
let _: Token![:] = input.parse()?;
// the name of our event enum
let name: EventKind = input.parse()?;
let _: Token![,] = input.parse()?;
// "events" field
let _: kw::events = input.parse()?;
let _: Token![:] = input.parse()?;
// an array of event names `["m.room.whatever", ...]`
let content;
bracketed!(content in input);
let events = content.parse_terminated::<_, Token![,]>(EventEnumEntry::parse)?;
let events = events.into_iter().collect();
Ok(Self { attrs, name, events })
}
}
pub struct EventEnumEntry {
pub attrs: Vec<Attribute>,
pub ev_type: LitStr,
@ -236,3 +194,44 @@ impl Parse for EventEnumEntry {
Ok(Self { attrs: input.call(Attribute::parse_outer)?, ev_type: input.parse()? })
}
}
/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumDecl {
/// Outer attributes on the field, such as a docstring.
pub attrs: Vec<Attribute>,
/// The name of the event.
pub name: EventKind,
/// An array of valid matrix event types.
///
/// This will generate the variants of the event type "kind". 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<EventEnumEntry>,
}
/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumInput {
pub(crate) enums: Vec<EventEnumDecl>,
}
impl Parse for EventEnumInput {
fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
let mut enums = vec![];
while !input.is_empty() {
let attrs = input.call(Attribute::parse_outer)?;
let _: Token![enum] = input.parse()?;
let name: EventKind = input.parse()?;
let content;
braced!(content in input);
let events = content.parse_terminated::<_, Token![,]>(EventEnumEntry::parse)?;
let events = events.into_iter().collect();
enums.push(EventEnumDecl { attrs, name, events });
}
Ok(EventEnumInput { enums })
}
}

View File

@ -0,0 +1,176 @@
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{Ident, LitStr};
use crate::event_parse::{EventEnumEntry, EventEnumInput, EventKind};
pub fn expand_event_type_enum(
input: EventEnumInput,
ruma_events: TokenStream,
) -> syn::Result<TokenStream> {
let ruma_serde = quote! { #ruma_events::exports::ruma_serde };
let mut room: Vec<&Vec<EventEnumEntry>> = vec![];
let mut state: Vec<&Vec<EventEnumEntry>> = vec![];
let mut message: Vec<&Vec<EventEnumEntry>> = vec![];
let mut ephemeral: Vec<&Vec<EventEnumEntry>> = vec![];
let mut room_account: Vec<&Vec<EventEnumEntry>> = vec![];
let mut global_account: Vec<&Vec<EventEnumEntry>> = vec![];
let mut to_device: Vec<&Vec<EventEnumEntry>> = vec![];
for event in &input.enums {
match event.name {
EventKind::GlobalAccountData => global_account.push(&event.events),
EventKind::RoomAccountData => room_account.push(&event.events),
EventKind::Ephemeral => ephemeral.push(&event.events),
EventKind::Message => {
message.push(&event.events);
room.push(&event.events);
}
EventKind::State => {
state.push(&event.events);
room.push(&event.events);
}
EventKind::ToDevice => to_device.push(&event.events),
EventKind::Redaction => {}
EventKind::Presence => {}
}
}
let presence = vec![EventEnumEntry {
attrs: vec![],
ev_type: LitStr::new("m.presence", Span::call_site()),
}];
let mut all = input.enums.iter().map(|e| &e.events).collect::<Vec<_>>();
all.push(&presence);
let (all_event_types, all_str_ev_types) = generate_variants(&all)?;
let all =
generate_enum(format_ident!("EventType"), all_str_ev_types, all_event_types, &ruma_serde);
let (room_event_types, room_str_ev_types) = generate_variants(&room)?;
let room = generate_enum(
format_ident!("RoomEventType"),
room_str_ev_types,
room_event_types,
&ruma_serde,
);
let (state_event_types, state_str_ev_types) = generate_variants(&state)?;
let state = generate_enum(
format_ident!("StateEventType"),
state_str_ev_types,
state_event_types,
&ruma_serde,
);
let (message_event_types, message_str_ev_types) = generate_variants(&message)?;
let message = generate_enum(
format_ident!("MessageEventType"),
message_str_ev_types,
message_event_types,
&ruma_serde,
);
let (ephemeral_event_types, ephemeral_str_ev_types) = generate_variants(&ephemeral)?;
let ephemeral = generate_enum(
format_ident!("EphemeralRoomEventType"),
ephemeral_str_ev_types,
ephemeral_event_types,
&ruma_serde,
);
let (room_account_event_types, room_account_str_ev_types) = generate_variants(&room_account)?;
let room_account = generate_enum(
format_ident!("RoomAccountDataEventType"),
room_account_str_ev_types,
room_account_event_types,
&ruma_serde,
);
let (global_account_event_types, global_account_str_ev_types) =
generate_variants(&global_account)?;
let global_account = generate_enum(
format_ident!("GlobalAccountDataEventType"),
global_account_str_ev_types,
global_account_event_types,
&ruma_serde,
);
let (to_device_event_types, to_device_str_ev_types) = generate_variants(&to_device)?;
let to_device = generate_enum(
format_ident!("ToDeviceEventType"),
to_device_str_ev_types,
to_device_event_types,
&ruma_serde,
);
Ok(quote! {
#all
#room
#state
#message
#ephemeral
#room_account
#global_account
#to_device
})
}
fn generate_enum(
ident: Ident,
ev_type_strings: Vec<&LitStr>,
variants: Vec<TokenStream>,
ruma_serde: &TokenStream,
) -> TokenStream {
let str_doc = format!("Creates a string slice from this `{}`.", ident);
let byte_doc = format!("Creates a byte slice from this `{}`.", ident);
let enum_doc = format!("The type of `{}` this is.", ident);
quote! {
#[doc = #enum_doc]
///
/// This type can hold an arbitrary string. To check for events that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, #ruma_serde::StringEnum)]
pub enum #ident {
#(
#[doc = #ev_type_strings]
#[ruma_enum(rename = #ev_type_strings)]
#variants,
)*
#[doc(hidden)]
_Custom(String),
}
impl #ident {
#[doc = #str_doc]
pub fn as_str(&self) -> &str {
self.as_ref()
}
#[doc = #byte_doc]
pub fn as_bytes(&self) -> &[u8] {
self.as_str().as_bytes()
}
}
}
}
fn generate_variants<'a>(
input: &'a [&Vec<EventEnumEntry>],
) -> syn::Result<(Vec<TokenStream>, Vec<&'a LitStr>)> {
let mut deduped: Vec<&EventEnumEntry> = vec![];
for item in input.iter().copied().flatten() {
if let Some(idx) = deduped.iter().position(|e| e.ev_type == item.ev_type) {
// If there is a variant without config attributes use that
if deduped[idx].attrs != item.attrs && item.attrs.is_empty() {
deduped[idx] = item;
}
} else {
deduped.push(item);
}
}
let event_types = deduped.iter().map(|e| &e.ev_type).collect();
let event_types_variants =
deduped.iter().map(|e| Ok(e.to_variant()?.decl())).collect::<syn::Result<Vec<_>>>()?;
Ok((event_types_variants, event_types))
}

View File

@ -8,6 +8,7 @@
#![warn(missing_docs)]
use event_parse::EventEnumInput;
use proc_macro::TokenStream;
use proc_macro2 as pm2;
use proc_macro_crate::{crate_name, FoundCrate};
@ -16,13 +17,15 @@ use syn::{parse_macro_input, DeriveInput, Ident};
use self::{
event::expand_event, event_content::expand_event_content, event_enum::expand_event_enum,
event_parse::EventEnumInput,
event_type::expand_event_type_enum,
};
mod event;
mod event_content;
mod event_enum;
mod event_parse;
mod event_type;
/// Generates an enum to represent the various Matrix event types.
///
/// This macro also implements the necessary traits for the type to serialize and deserialize
@ -35,20 +38,40 @@ mod event_parse;
/// use ruma_events_macros::event_enum;
///
/// event_enum! {
/// kind: ToDevice,
/// events: [
/// enum ToDevice {
/// "m.any.event",
/// "m.other.event",
/// ]
/// }
///
/// enum State {
/// "m.more.events",
/// "m.different.event",
/// }
/// }
/// ```
/// (The argument to `kind` has to be a valid identifier for `<EventKind as Parse>::parse`)
/// (The enum name has to be a valid identifier for `<EventKind as Parse>::parse`)
//// TODO: Change above (`<EventKind as Parse>::parse`) to [] after fully qualified syntax is
//// supported: https://github.com/rust-lang/rust/issues/74563
#[proc_macro]
pub fn event_enum(input: TokenStream) -> TokenStream {
let ruma_events = import_ruma_events();
let event_enum_input = syn::parse_macro_input!(input as EventEnumInput);
expand_event_enum(event_enum_input).unwrap_or_else(syn::Error::into_compile_error).into()
let enums = event_enum_input
.enums
.iter()
.map(expand_event_enum)
.collect::<syn::Result<pm2::TokenStream>>();
let event_types = expand_event_type_enum(event_enum_input, ruma_events);
event_types
.and_then(|types| {
enums.map(|mut enums| {
enums.extend(types);
enums
})
})
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
/// Generates an implementation of `ruma_events::EventContent`.

View File

@ -6,36 +6,26 @@ use crate::{from_raw_json_value, EventDeHelper};
event_enum! {
/// Any global account data event.
kind: GlobalAccountData,
events: [
enum GlobalAccountData {
"m.direct",
"m.ignored_user_list",
"m.push_rules",
]
}
event_enum! {
/// Any room account data event.
kind: RoomAccountData,
events: [
enum RoomAccountData {
"m.fully_read",
"m.tag",
]
}
event_enum! {
/// Any ephemeral room event.
kind: EphemeralRoom,
events: [
enum EphemeralRoom {
"m.receipt",
"m.typing",
]
}
event_enum! {
/// Any message event.
kind: Message,
events: [
enum Message {
"m.call.answer",
"m.call.invite",
"m.call.hangup",
@ -69,13 +59,11 @@ event_enum! {
"m.room.message.feedback",
"m.room.redaction",
"m.sticker",
]
}
event_enum! {
/// Any state event.
kind: State,
events: [
enum State {
"m.policy.rule.room",
"m.policy.rule.server",
"m.policy.rule.user",
@ -95,13 +83,10 @@ event_enum! {
"m.room.third_party_invite",
"m.room.tombstone",
"m.room.topic",
]
}
event_enum! {
/// Any to-device event.
kind: ToDevice,
events: [
enum ToDevice {
"m.dummy",
"m.room_key",
"m.room_key_request",
@ -119,7 +104,7 @@ event_enum! {
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
"m.key.verification.done",
"m.room.encrypted",
]
}
}
/// Any room event.

View File

@ -1,278 +0,0 @@
use ruma_serde::StringEnum;
/// The type of an event.
///
/// This type can hold an arbitrary string. To check for events that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
// FIXME: Add `m.foo.bar` or `m.foo_bar` as a naming scheme in StringEnum and remove most rename
// attributes.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, StringEnum)]
pub enum EventType {
/// m.call.answer
#[ruma_enum(rename = "m.call.answer")]
CallAnswer,
/// m.call.candidates
#[ruma_enum(rename = "m.call.candidates")]
CallCandidates,
/// m.call.hangup
#[ruma_enum(rename = "m.call.hangup")]
CallHangup,
/// m.call.invite
#[ruma_enum(rename = "m.call.invite")]
CallInvite,
/// m.direct
#[ruma_enum(rename = "m.direct")]
Direct,
/// m.dummy
#[ruma_enum(rename = "m.dummy")]
Dummy,
/// m.forwarded_room_key
#[ruma_enum(rename = "m.forwarded_room_key")]
ForwardedRoomKey,
/// m.fully_read
#[ruma_enum(rename = "m.fully_read")]
FullyRead,
/// m.key.verification.accept
#[ruma_enum(rename = "m.key.verification.accept")]
KeyVerificationAccept,
/// m.key.verification.cancel
#[ruma_enum(rename = "m.key.verification.cancel")]
KeyVerificationCancel,
/// m.key.verification.done
#[ruma_enum(rename = "m.key.verification.done")]
KeyVerificationDone,
/// m.key.verification.key
#[ruma_enum(rename = "m.key.verification.key")]
KeyVerificationKey,
/// m.key.verification.mac
#[ruma_enum(rename = "m.key.verification.mac")]
KeyVerificationMac,
/// m.key.verification.ready
#[ruma_enum(rename = "m.key.verification.ready")]
KeyVerificationReady,
/// m.key.verification.request
#[ruma_enum(rename = "m.key.verification.request")]
KeyVerificationRequest,
/// m.key.verification.start
#[ruma_enum(rename = "m.key.verification.start")]
KeyVerificationStart,
/// m.ignored_user_list
#[ruma_enum(rename = "m.ignored_user_list")]
IgnoredUserList,
/// m.policy.rule.room
#[ruma_enum(rename = "m.policy.rule.room")]
PolicyRuleRoom,
/// m.policy.rule.server
#[ruma_enum(rename = "m.policy.rule.server")]
PolicyRuleServer,
/// m.policy.rule.user
#[ruma_enum(rename = "m.policy.rule.user")]
PolicyRuleUser,
/// m.presence
#[ruma_enum(rename = "m.presence")]
Presence,
/// m.push_rules
#[ruma_enum(rename = "m.push_rules")]
PushRules,
/// m.receipt
#[ruma_enum(rename = "m.receipt")]
Receipt,
/// m.room.aliases
#[ruma_enum(rename = "m.room.aliases")]
RoomAliases,
/// m.room.avatar
#[ruma_enum(rename = "m.room.avatar")]
RoomAvatar,
/// m.room.canonical_alias
#[ruma_enum(rename = "m.room.canonical_alias")]
RoomCanonicalAlias,
/// m.room.create
#[ruma_enum(rename = "m.room.create")]
RoomCreate,
/// m.room.encrypted
#[ruma_enum(rename = "m.room.encrypted")]
RoomEncrypted,
/// m.room.encryption
#[ruma_enum(rename = "m.room.encryption")]
RoomEncryption,
/// m.room.guest_access
#[ruma_enum(rename = "m.room.guest_access")]
RoomGuestAccess,
/// m.room.history_visibility
#[ruma_enum(rename = "m.room.history_visibility")]
RoomHistoryVisibility,
/// m.room.join_rules
#[ruma_enum(rename = "m.room.join_rules")]
RoomJoinRules,
/// m.room.member
#[ruma_enum(rename = "m.room.member")]
RoomMember,
/// m.room.message
#[ruma_enum(rename = "m.room.message")]
RoomMessage,
/// m.room.message.feedback
#[ruma_enum(rename = "m.room.message.feedback")]
RoomMessageFeedback,
/// m.room.name
#[ruma_enum(rename = "m.room.name")]
RoomName,
/// m.room.pinned_events
#[ruma_enum(rename = "m.room.pinned_events")]
RoomPinnedEvents,
/// m.room.power_levels
#[ruma_enum(rename = "m.room.power_levels")]
RoomPowerLevels,
/// m.room.redaction
#[ruma_enum(rename = "m.room.redaction")]
RoomRedaction,
/// m.room.server_acl
#[ruma_enum(rename = "m.room.server_acl")]
RoomServerAcl,
/// m.room.third_party_invite
#[ruma_enum(rename = "m.room.third_party_invite")]
RoomThirdPartyInvite,
/// m.room.tombstone
#[ruma_enum(rename = "m.room.tombstone")]
RoomTombstone,
/// m.room.topic
#[ruma_enum(rename = "m.room.topic")]
RoomTopic,
/// m.room_key
#[ruma_enum(rename = "m.room_key")]
RoomKey,
/// m.room_key_request
#[ruma_enum(rename = "m.room_key_request")]
RoomKeyRequest,
/// m.sticker
#[ruma_enum(rename = "m.sticker")]
Sticker,
/// m.tag
#[ruma_enum(rename = "m.tag")]
Tag,
/// m.typing
#[ruma_enum(rename = "m.typing")]
Typing,
#[doc(hidden)]
_Custom(String),
}
impl EventType {
/// Creates a string slice from this `EventType`.
pub fn as_str(&self) -> &str {
self.as_ref()
}
/// Creates a byte slice from this `EventType`.
pub fn as_bytes(&self) -> &[u8] {
self.as_str().as_bytes()
}
}
#[cfg(test)]
mod tests {
use ruma_serde::test::serde_json_eq;
use serde_json::json;
use super::EventType;
#[test]
fn serialize_and_deserialize_from_display_form() {
serde_json_eq(EventType::CallAnswer, json!("m.call.answer"));
serde_json_eq(EventType::CallCandidates, json!("m.call.candidates"));
serde_json_eq(EventType::CallHangup, json!("m.call.hangup"));
serde_json_eq(EventType::CallInvite, json!("m.call.invite"));
serde_json_eq(EventType::Direct, json!("m.direct"));
serde_json_eq(EventType::Dummy, json!("m.dummy"));
serde_json_eq(EventType::ForwardedRoomKey, json!("m.forwarded_room_key"));
serde_json_eq(EventType::FullyRead, json!("m.fully_read"));
serde_json_eq(EventType::KeyVerificationAccept, json!("m.key.verification.accept"));
serde_json_eq(EventType::KeyVerificationCancel, json!("m.key.verification.cancel"));
serde_json_eq(EventType::KeyVerificationDone, json!("m.key.verification.done"));
serde_json_eq(EventType::KeyVerificationKey, json!("m.key.verification.key"));
serde_json_eq(EventType::KeyVerificationMac, json!("m.key.verification.mac"));
serde_json_eq(EventType::KeyVerificationReady, json!("m.key.verification.ready"));
serde_json_eq(EventType::KeyVerificationRequest, json!("m.key.verification.request"));
serde_json_eq(EventType::KeyVerificationStart, json!("m.key.verification.start"));
serde_json_eq(EventType::IgnoredUserList, json!("m.ignored_user_list"));
serde_json_eq(EventType::PolicyRuleRoom, json!("m.policy.rule.room"));
serde_json_eq(EventType::PolicyRuleServer, json!("m.policy.rule.server"));
serde_json_eq(EventType::PolicyRuleUser, json!("m.policy.rule.user"));
serde_json_eq(EventType::Presence, json!("m.presence"));
serde_json_eq(EventType::PushRules, json!("m.push_rules"));
serde_json_eq(EventType::Receipt, json!("m.receipt"));
serde_json_eq(EventType::RoomAliases, json!("m.room.aliases"));
serde_json_eq(EventType::RoomAvatar, json!("m.room.avatar"));
serde_json_eq(EventType::RoomCanonicalAlias, json!("m.room.canonical_alias"));
serde_json_eq(EventType::RoomCreate, json!("m.room.create"));
serde_json_eq(EventType::RoomEncrypted, json!("m.room.encrypted"));
serde_json_eq(EventType::RoomEncryption, json!("m.room.encryption"));
serde_json_eq(EventType::RoomGuestAccess, json!("m.room.guest_access"));
serde_json_eq(EventType::RoomHistoryVisibility, json!("m.room.history_visibility"));
serde_json_eq(EventType::RoomJoinRules, json!("m.room.join_rules"));
serde_json_eq(EventType::RoomMember, json!("m.room.member"));
serde_json_eq(EventType::RoomMessage, json!("m.room.message"));
serde_json_eq(EventType::RoomMessageFeedback, json!("m.room.message.feedback"));
serde_json_eq(EventType::RoomName, json!("m.room.name"));
serde_json_eq(EventType::RoomPinnedEvents, json!("m.room.pinned_events"));
serde_json_eq(EventType::RoomPowerLevels, json!("m.room.power_levels"));
serde_json_eq(EventType::RoomRedaction, json!("m.room.redaction"));
serde_json_eq(EventType::RoomServerAcl, json!("m.room.server_acl"));
serde_json_eq(EventType::RoomThirdPartyInvite, json!("m.room.third_party_invite"));
serde_json_eq(EventType::RoomTombstone, json!("m.room.tombstone"));
serde_json_eq(EventType::RoomTopic, json!("m.room.topic"));
serde_json_eq(EventType::RoomKey, json!("m.room_key"));
serde_json_eq(EventType::RoomKeyRequest, json!("m.room_key_request"));
serde_json_eq(EventType::Sticker, json!("m.sticker"));
serde_json_eq(EventType::Tag, json!("m.tag"));
serde_json_eq(EventType::Typing, json!("m.typing"));
serde_json_eq(EventType::_Custom("io.ruma.test".into()), json!("io.ruma.test"));
}
}

View File

@ -131,7 +131,6 @@ use self::room::redaction::{RedactionEvent, SyncRedactionEvent};
mod enums;
mod error;
mod event_kinds;
mod event_type;
// Hack to allow both ruma-events itself and external crates (or tests) to use procedural macros
// that expect `ruma_events` to exist in the prelude.
@ -145,6 +144,7 @@ extern crate self as ruma_events;
pub mod exports {
pub use ruma_common;
pub use ruma_identifiers;
pub use ruma_serde;
pub use serde;
pub use serde_json;
}
@ -194,7 +194,9 @@ pub use self::{
AnyRoomAccountDataEvent, AnyRoomAccountDataEventContent, AnyRoomEvent, AnyStateEvent,
AnyStateEventContent, AnyStrippedStateEvent, AnySyncEphemeralRoomEvent,
AnySyncMessageEvent, AnySyncRoomEvent, AnySyncStateEvent, AnyToDeviceEvent,
AnyToDeviceEventContent,
AnyToDeviceEventContent, EphemeralRoomEventType, EventType, GlobalAccountDataEventType,
MessageEventType, RoomAccountDataEventType, RoomEventType, StateEventType,
ToDeviceEventType,
},
error::{FromStrError, InvalidInput},
event_kinds::{
@ -204,7 +206,6 @@ pub use self::{
StrippedStateEvent, SyncEphemeralRoomEvent, SyncMessageEvent, SyncStateEvent,
ToDeviceEvent,
},
event_type::EventType,
};
/// Extra information about an event that is not incorporated into the event's

View File

@ -2,6 +2,7 @@ use js_int::uint;
use matches::assert_matches;
use ruma_common::MilliSecondsSinceUnixEpoch;
use ruma_identifiers::{event_id, room_alias_id, room_id, user_id};
use ruma_serde::test::serde_json_eq;
use serde_json::{from_value as from_json_value, json, Value as JsonValue};
use ruma_events::{
@ -11,8 +12,9 @@ use ruma_events::{
power_levels::PowerLevelsEventContent,
},
AnyEphemeralRoomEvent, AnyMessageEvent, AnyRoomEvent, AnyStateEvent, AnyStateEventContent,
AnySyncMessageEvent, AnySyncRoomEvent, AnySyncStateEvent, MessageEvent, StateEvent,
SyncMessageEvent, SyncStateEvent, Unsigned,
AnySyncMessageEvent, AnySyncRoomEvent, AnySyncStateEvent, EphemeralRoomEventType, EventType,
GlobalAccountDataEventType, MessageEvent, MessageEventType, RoomAccountDataEventType,
StateEvent, StateEventType, SyncMessageEvent, SyncStateEvent, ToDeviceEventType, Unsigned,
};
fn message_event() -> JsonValue {
@ -316,3 +318,64 @@ fn ephemeral_event_deserialization() {
if ephem.room_id() == &room_id!("!jEsUZKDJdhlrceRyVU:example.org")
);
}
#[test]
fn serialize_and_deserialize_from_display_form() {
serde_json_eq(EventType::CallAnswer, json!("m.call.answer"));
serde_json_eq(MessageEventType::CallAnswer, json!("m.call.answer"));
serde_json_eq(EventType::CallCandidates, json!("m.call.candidates"));
serde_json_eq(EventType::CallHangup, json!("m.call.hangup"));
serde_json_eq(EventType::CallInvite, json!("m.call.invite"));
serde_json_eq(EventType::Direct, json!("m.direct"));
serde_json_eq(GlobalAccountDataEventType::Direct, json!("m.direct"));
serde_json_eq(EventType::Dummy, json!("m.dummy"));
serde_json_eq(EventType::ForwardedRoomKey, json!("m.forwarded_room_key"));
serde_json_eq(EventType::FullyRead, json!("m.fully_read"));
serde_json_eq(RoomAccountDataEventType::FullyRead, json!("m.fully_read"));
serde_json_eq(EventType::KeyVerificationAccept, json!("m.key.verification.accept"));
serde_json_eq(EventType::KeyVerificationCancel, json!("m.key.verification.cancel"));
// m.key.verification.ready is unstable-pre-spec
// serde_json_eq(EventType::KeyVerificationDone, json!("m.key.verification.done"));
serde_json_eq(EventType::KeyVerificationKey, json!("m.key.verification.key"));
serde_json_eq(ToDeviceEventType::KeyVerificationKey, json!("m.key.verification.key"));
serde_json_eq(EventType::KeyVerificationMac, json!("m.key.verification.mac"));
// m.key.verification.ready is unstable-pre-spec
// serde_json_eq(EventType::KeyVerificationReady, json!("m.key.verification.ready"));
serde_json_eq(EventType::KeyVerificationRequest, json!("m.key.verification.request"));
serde_json_eq(EventType::KeyVerificationStart, json!("m.key.verification.start"));
serde_json_eq(EventType::IgnoredUserList, json!("m.ignored_user_list"));
serde_json_eq(EventType::PolicyRuleRoom, json!("m.policy.rule.room"));
serde_json_eq(EventType::PolicyRuleServer, json!("m.policy.rule.server"));
serde_json_eq(EventType::PolicyRuleUser, json!("m.policy.rule.user"));
serde_json_eq(EventType::Presence, json!("m.presence"));
serde_json_eq(EventType::PushRules, json!("m.push_rules"));
serde_json_eq(EventType::Receipt, json!("m.receipt"));
serde_json_eq(EventType::RoomAliases, json!("m.room.aliases"));
serde_json_eq(EventType::RoomAvatar, json!("m.room.avatar"));
serde_json_eq(EventType::RoomCanonicalAlias, json!("m.room.canonical_alias"));
serde_json_eq(EventType::RoomCreate, json!("m.room.create"));
serde_json_eq(StateEventType::RoomCreate, json!("m.room.create"));
serde_json_eq(EventType::RoomEncrypted, json!("m.room.encrypted"));
serde_json_eq(EventType::RoomEncryption, json!("m.room.encryption"));
serde_json_eq(EventType::RoomGuestAccess, json!("m.room.guest_access"));
serde_json_eq(EventType::RoomHistoryVisibility, json!("m.room.history_visibility"));
serde_json_eq(EventType::RoomJoinRules, json!("m.room.join_rules"));
serde_json_eq(EventType::RoomMember, json!("m.room.member"));
serde_json_eq(EventType::RoomMessage, json!("m.room.message"));
serde_json_eq(EventType::RoomMessageFeedback, json!("m.room.message.feedback"));
serde_json_eq(EventType::RoomName, json!("m.room.name"));
serde_json_eq(EventType::RoomPinnedEvents, json!("m.room.pinned_events"));
serde_json_eq(EventType::RoomPowerLevels, json!("m.room.power_levels"));
serde_json_eq(EventType::RoomRedaction, json!("m.room.redaction"));
serde_json_eq(EventType::RoomServerAcl, json!("m.room.server_acl"));
serde_json_eq(EventType::RoomThirdPartyInvite, json!("m.room.third_party_invite"));
serde_json_eq(EventType::RoomTombstone, json!("m.room.tombstone"));
serde_json_eq(EventType::RoomTopic, json!("m.room.topic"));
serde_json_eq(EventType::RoomKey, json!("m.room_key"));
serde_json_eq(EventType::RoomKeyRequest, json!("m.room_key_request"));
serde_json_eq(EventType::Sticker, json!("m.sticker"));
serde_json_eq(EventType::Tag, json!("m.tag"));
serde_json_eq(EventType::Typing, json!("m.typing"));
serde_json_eq(EphemeralRoomEventType::Typing, json!("m.typing"));
serde_json_eq(EventType::_Custom("io.ruma.test".into()), json!("io.ruma.test"));
}

View File

@ -2,15 +2,14 @@ use ruma_events_macros::event_enum;
event_enum! {
/// Any global account data event.
kind: GlobalAccountData,
events: [
enum GlobalAccountData {
"m.direct",
#[cfg(test)]
"m.ignored_user_list",
"m.push_rules",
#[cfg(any())]
"m.ruma_test",
]
}
}
fn main() {}

View File

@ -1,17 +1,15 @@
use ruma_events_macros::event_enum;
event_enum! {
kind: State,
events: [
enum State {
"m.not.a.path",
]
}
}
event_enum! {
kind: State,
events: [
enum State {
"not.a.path",
]
}
}
fn main() {}

View File

@ -1,11 +1,11 @@
error: well-known matrix events have to start with `m.` found `not.a.path`
--> $DIR/08-enum-invalid-path.rs:13:9
--> $DIR/08-enum-invalid-path.rs:11:9
|
13 | "not.a.path",
11 | "not.a.path",
| ^^^^^^^^^^^^
error[E0433]: failed to resolve: could not find `not` in `ruma_events`
--> $DIR/08-enum-invalid-path.rs:6:9
--> $DIR/08-enum-invalid-path.rs:5:9
|
6 | "m.not.a.path",
5 | "m.not.a.path",
| ^^^^^^^^^^^^^^ could not find `not` in `ruma_events`

View File

@ -1,14 +1,13 @@
use ruma_events_macros::event_enum;
event_enum! {
kind: NotReal,
events: [
enum NotReal {
"m.direct",
"m.dummy",
"m.ignored_user_list",
"m.push_rules",
"m.room_key",
]
}
}
fn main() {}

View File

@ -1,5 +1,5 @@
error: valid event kinds are GlobalAccountData, RoomAccountData, EphemeralRoom, Message, State, ToDevice found `NotReal`
--> $DIR/09-enum-invalid-kind.rs:4:18
--> $DIR/09-enum-invalid-kind.rs:4:10
|
4 | kind: NotReal,
| ^
4 | enum NotReal {
| ^^^^^^^