From d1f5fb1d876627f0370530550329d0612d637d43 Mon Sep 17 00:00:00 2001 From: Devin Ragotzy Date: Fri, 14 May 2021 19:52:34 -0400 Subject: [PATCH] events: Declare all event enums inside one macro invocation --- crates/ruma-events-macros/src/event_enum.rs | 16 +- crates/ruma-events-macros/src/event_parse.rs | 89 +++--- crates/ruma-events-macros/src/event_type.rs | 176 +++++++++++ crates/ruma-events-macros/src/lib.rs | 35 ++- crates/ruma-events/src/enums.rs | 41 +-- crates/ruma-events/src/event_type.rs | 278 ------------------ crates/ruma-events/src/lib.rs | 7 +- crates/ruma-events/tests/enums.rs | 67 ++++- .../tests/ui/07-enum-sanity-check.rs | 5 +- .../tests/ui/08-enum-invalid-path.rs | 10 +- .../tests/ui/08-enum-invalid-path.stderr | 8 +- .../tests/ui/09-enum-invalid-kind.rs | 5 +- .../tests/ui/09-enum-invalid-kind.stderr | 6 +- 13 files changed, 354 insertions(+), 389 deletions(-) create mode 100644 crates/ruma-events-macros/src/event_type.rs delete mode 100644 crates/ruma-events/src/event_type.rs diff --git a/crates/ruma-events-macros/src/event_enum.rs b/crates/ruma-events-macros/src/event_enum.rs index ba2516d9..3a93f9c0 100644 --- a/crates/ruma-events-macros/src/event_enum.rs +++ b/crates/ruma-events-macros/src/event_enum.rs @@ -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 { +pub fn expand_event_enum(input: &EventEnumDecl) -> syn::Result { 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, pub ident: Ident, } impl EventEnumVariant { - fn to_tokens(&self, prefix: Option, with_attrs: bool) -> TokenStream + pub(crate) fn to_tokens(&self, prefix: Option, 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::(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 { + pub(crate) fn to_variant(&self) -> syn::Result { let attrs = self.attrs.clone(); let ident = to_camel_case(&self.ev_type)?; Ok(EventEnumVariant { attrs, ident }) diff --git a/crates/ruma-events-macros/src/event_parse.rs b/crates/ruma-events-macros/src/event_parse.rs index 8097e096..41372cae 100644 --- a/crates/ruma-events-macros/src/event_parse.rs +++ b/crates/ruma-events-macros/src/event_parse.rs @@ -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, - - /// 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, -} - -impl Parse for EventEnumInput { - fn parse(input: ParseStream<'_>) -> parse::Result { - 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, 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, + + /// 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, +} + +/// The entire `event_enum!` macro structure directly as it appears in the source code. +pub struct EventEnumInput { + pub(crate) enums: Vec, +} + +impl Parse for EventEnumInput { + fn parse(input: ParseStream<'_>) -> parse::Result { + 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 }) + } +} diff --git a/crates/ruma-events-macros/src/event_type.rs b/crates/ruma-events-macros/src/event_type.rs new file mode 100644 index 00000000..028de31c --- /dev/null +++ b/crates/ruma-events-macros/src/event_type.rs @@ -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 { + let ruma_serde = quote! { #ruma_events::exports::ruma_serde }; + + let mut room: Vec<&Vec> = vec![]; + let mut state: Vec<&Vec> = vec![]; + let mut message: Vec<&Vec> = vec![]; + let mut ephemeral: Vec<&Vec> = vec![]; + let mut room_account: Vec<&Vec> = vec![]; + let mut global_account: Vec<&Vec> = vec![]; + let mut to_device: Vec<&Vec> = 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::>(); + 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, + 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], +) -> syn::Result<(Vec, 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::>>()?; + + Ok((event_types_variants, event_types)) +} diff --git a/crates/ruma-events-macros/src/lib.rs b/crates/ruma-events-macros/src/lib.rs index fc4fdf51..9fb87562 100644 --- a/crates/ruma-events-macros/src/lib.rs +++ b/crates/ruma-events-macros/src/lib.rs @@ -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 `::parse`) +/// (The enum name has to be a valid identifier for `::parse`) //// TODO: Change above (`::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::>(); + 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`. diff --git a/crates/ruma-events/src/enums.rs b/crates/ruma-events/src/enums.rs index 8de18163..0db0f90c 100644 --- a/crates/ruma-events/src/enums.rs +++ b/crates/ruma-events/src/enums.rs @@ -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. diff --git a/crates/ruma-events/src/event_type.rs b/crates/ruma-events/src/event_type.rs deleted file mode 100644 index b2d75484..00000000 --- a/crates/ruma-events/src/event_type.rs +++ /dev/null @@ -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")); - } -} diff --git a/crates/ruma-events/src/lib.rs b/crates/ruma-events/src/lib.rs index acbf8b8e..932e3a06 100644 --- a/crates/ruma-events/src/lib.rs +++ b/crates/ruma-events/src/lib.rs @@ -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 diff --git a/crates/ruma-events/tests/enums.rs b/crates/ruma-events/tests/enums.rs index 494ccb03..94cc9eff 100644 --- a/crates/ruma-events/tests/enums.rs +++ b/crates/ruma-events/tests/enums.rs @@ -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")); +} diff --git a/crates/ruma-events/tests/ui/07-enum-sanity-check.rs b/crates/ruma-events/tests/ui/07-enum-sanity-check.rs index 83ac5a53..f32172fe 100644 --- a/crates/ruma-events/tests/ui/07-enum-sanity-check.rs +++ b/crates/ruma-events/tests/ui/07-enum-sanity-check.rs @@ -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() {} diff --git a/crates/ruma-events/tests/ui/08-enum-invalid-path.rs b/crates/ruma-events/tests/ui/08-enum-invalid-path.rs index 2f6e1367..ff5d4829 100644 --- a/crates/ruma-events/tests/ui/08-enum-invalid-path.rs +++ b/crates/ruma-events/tests/ui/08-enum-invalid-path.rs @@ -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() {} diff --git a/crates/ruma-events/tests/ui/08-enum-invalid-path.stderr b/crates/ruma-events/tests/ui/08-enum-invalid-path.stderr index 48062907..6656a3d9 100644 --- a/crates/ruma-events/tests/ui/08-enum-invalid-path.stderr +++ b/crates/ruma-events/tests/ui/08-enum-invalid-path.stderr @@ -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` diff --git a/crates/ruma-events/tests/ui/09-enum-invalid-kind.rs b/crates/ruma-events/tests/ui/09-enum-invalid-kind.rs index f3597fe0..b21b75fe 100644 --- a/crates/ruma-events/tests/ui/09-enum-invalid-kind.rs +++ b/crates/ruma-events/tests/ui/09-enum-invalid-kind.rs @@ -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() {} diff --git a/crates/ruma-events/tests/ui/09-enum-invalid-kind.stderr b/crates/ruma-events/tests/ui/09-enum-invalid-kind.stderr index 4a1cc655..afeae5fa 100644 --- a/crates/ruma-events/tests/ui/09-enum-invalid-kind.stderr +++ b/crates/ruma-events/tests/ui/09-enum-invalid-kind.stderr @@ -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 { + | ^^^^^^^