macros: Require event module path for event_enum

This commit is contained in:
Kévin Commaille 2022-05-03 12:09:45 +02:00 committed by Kévin Commaille
parent 82a4bb2e2b
commit 3ddc4de758
7 changed files with 114 additions and 112 deletions

View File

@ -15,108 +15,108 @@ use crate::{
event_enum! { event_enum! {
/// Any global account data event. /// Any global account data event.
enum GlobalAccountData { enum GlobalAccountData {
"m.direct", "m.direct" => super::direct,
"m.identity_server", "m.identity_server" => super::identity_server,
"m.ignored_user_list", "m.ignored_user_list" => super::ignored_user_list,
"m.push_rules", "m.push_rules" => super::push_rules,
"m.secret_storage.default_key", "m.secret_storage.default_key" => super::secret_storage::default_key,
"m.secret_storage.key.*", "m.secret_storage.key.*" => super::secret_storage::key,
} }
/// Any room account data event. /// Any room account data event.
enum RoomAccountData { enum RoomAccountData {
"m.fully_read", "m.fully_read" => super::fully_read,
"m.tag", "m.tag" => super::tag,
} }
/// Any ephemeral room event. /// Any ephemeral room event.
enum EphemeralRoom { enum EphemeralRoom {
"m.receipt", "m.receipt" => super::receipt,
"m.typing", "m.typing" => super::typing,
} }
/// Any message-like event. /// Any message-like event.
enum MessageLike { enum MessageLike {
#[cfg(feature = "unstable-msc3246")] #[cfg(feature = "unstable-msc3246")]
"m.audio", "m.audio" => super::audio,
"m.call.answer", "m.call.answer" => super::call::answer,
"m.call.invite", "m.call.invite" => super::call::invite,
"m.call.hangup", "m.call.hangup" => super::call::hangup,
"m.call.candidates", "m.call.candidates" => super::call::candidates,
#[cfg(feature = "unstable-msc1767")] #[cfg(feature = "unstable-msc1767")]
"m.emote", "m.emote" => super::emote,
#[cfg(feature = "unstable-msc3551")] #[cfg(feature = "unstable-msc3551")]
"m.file", "m.file" => super::file,
#[cfg(feature = "unstable-msc3552")] #[cfg(feature = "unstable-msc3552")]
"m.image", "m.image" => super::image,
"m.key.verification.ready", "m.key.verification.ready" => super::key::verification::ready,
"m.key.verification.start", "m.key.verification.start" => super::key::verification::start,
"m.key.verification.cancel", "m.key.verification.cancel" => super::key::verification::cancel,
"m.key.verification.accept", "m.key.verification.accept" => super::key::verification::accept,
"m.key.verification.key", "m.key.verification.key" => super::key::verification::key,
"m.key.verification.mac", "m.key.verification.mac" => super::key::verification::mac,
"m.key.verification.done", "m.key.verification.done" => super::key::verification::done,
#[cfg(feature = "unstable-msc3488")] #[cfg(feature = "unstable-msc3488")]
"m.location", "m.location" => super::location,
#[cfg(feature = "unstable-msc1767")] #[cfg(feature = "unstable-msc1767")]
"m.message", "m.message" => super::message,
#[cfg(feature = "unstable-msc1767")] #[cfg(feature = "unstable-msc1767")]
"m.notice", "m.notice" => super::notice,
#[cfg(feature = "unstable-msc2677")] #[cfg(feature = "unstable-msc2677")]
"m.reaction", "m.reaction" => super::reaction,
"m.room.encrypted", "m.room.encrypted" => super::room::encrypted,
"m.room.message", "m.room.message" => super::room::message,
"m.room.message.feedback", "m.room.message.feedback" => super::room::message::feedback,
"m.room.redaction", "m.room.redaction" => super::room::redaction,
"m.sticker", "m.sticker" => super::sticker,
#[cfg(feature = "unstable-msc3553")] #[cfg(feature = "unstable-msc3553")]
"m.video", "m.video" => super::video,
#[cfg(feature = "unstable-msc3245")] #[cfg(feature = "unstable-msc3245")]
"m.voice", "m.voice" => super::voice,
} }
/// Any state event. /// Any state event.
enum State { enum State {
"m.policy.rule.room", "m.policy.rule.room" => super::policy::rule::room,
"m.policy.rule.server", "m.policy.rule.server" => super::policy::rule::server,
"m.policy.rule.user", "m.policy.rule.user" => super::policy::rule::user,
"m.room.aliases", "m.room.aliases" => super::room::aliases,
"m.room.avatar", "m.room.avatar" => super::room::avatar,
"m.room.canonical_alias", "m.room.canonical_alias" => super::room::canonical_alias,
"m.room.create", "m.room.create" => super::room::create,
"m.room.encryption", "m.room.encryption" => super::room::encryption,
"m.room.guest_access", "m.room.guest_access" => super::room::guest_access,
"m.room.history_visibility", "m.room.history_visibility" => super::room::history_visibility,
"m.room.join_rules", "m.room.join_rules" => super::room::join_rules,
"m.room.member", "m.room.member" => super::room::member,
"m.room.name", "m.room.name" => super::room::name,
"m.room.pinned_events", "m.room.pinned_events" => super::room::pinned_events,
"m.room.power_levels", "m.room.power_levels" => super::room::power_levels,
"m.room.server_acl", "m.room.server_acl" => super::room::server_acl,
"m.room.third_party_invite", "m.room.third_party_invite" => super::room::third_party_invite,
"m.room.tombstone", "m.room.tombstone" => super::room::tombstone,
"m.room.topic", "m.room.topic" => super::room::topic,
"m.space.child", "m.space.child" => super::space::child,
"m.space.parent", "m.space.parent" => super::space::parent,
} }
/// Any to-device event. /// Any to-device event.
enum ToDevice { enum ToDevice {
"m.dummy", "m.dummy" => super::dummy,
"m.room_key", "m.room_key" => super::room_key,
"m.room_key_request", "m.room_key_request" => super::room_key_request,
"m.forwarded_room_key", "m.forwarded_room_key" => super::forwarded_room_key,
"m.key.verification.request", "m.key.verification.request" => super::key::verification::request,
"m.key.verification.ready", "m.key.verification.ready" => super::key::verification::ready,
"m.key.verification.start", "m.key.verification.start" => super::key::verification::start,
"m.key.verification.cancel", "m.key.verification.cancel" => super::key::verification::cancel,
"m.key.verification.accept", "m.key.verification.accept" => super::key::verification::accept,
"m.key.verification.key", "m.key.verification.key" => super::key::verification::key,
"m.key.verification.mac", "m.key.verification.mac" => super::key::verification::mac,
"m.key.verification.done", "m.key.verification.done" => super::key::verification::done,
"m.room.encrypted", "m.room.encrypted" => super::room::encrypted,
"m.secret.request", "m.secret.request"=> super::secret::request,
"m.secret.send", "m.secret.send" => super::secret::send,
} }
} }

View File

@ -1,15 +1,16 @@
use ruma_common::events;
use ruma_macros::event_enum; use ruma_macros::event_enum;
event_enum! { event_enum! {
/// Any global account data event. /// Any global account data event.
enum GlobalAccountData { enum GlobalAccountData {
"m.direct", "m.direct" => events::direct,
#[cfg(test)] #[cfg(test)]
"m.ignored_user_list", "m.ignored_user_list" => events::ignored_user_list,
// Doesn't actually have a wildcard, but this should work as a wildcard test // Doesn't actually have a wildcard, but this should work as a wildcard test
"m.push_rules.*", "m.push_rules.*" => events::push_rules,
#[cfg(any())] #[cfg(any())]
"m.ruma_test", "m.ruma_test" => events::ruma_test,
} }
} }

View File

@ -1,8 +1,9 @@
use ruma_common::events;
use ruma_macros::event_enum; use ruma_macros::event_enum;
event_enum! { event_enum! {
enum State { enum State {
"m.not.a.path", "m.not.a.path" => events::not::a::path,
} }
} }

View File

@ -1,5 +1,5 @@
error[E0433]: failed to resolve: could not find `not` in `events` error[E0433]: failed to resolve: could not find `not` in `events`
--> tests/events/ui/08-enum-invalid-path.rs:5:9 --> tests/events/ui/08-enum-invalid-path.rs:6:35
| |
5 | "m.not.a.path", 6 | "m.not.a.path" => events::not::a::path,
| ^^^^^^^^^^^^^^ could not find `not` in `events` | ^^^ could not find `not` in `events`

View File

@ -4,7 +4,7 @@ use std::fmt;
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote, IdentFragment, ToTokens}; use quote::{format_ident, quote, IdentFragment, ToTokens};
use syn::{Attribute, Data, DataEnum, DeriveInput, Ident, LitStr}; use syn::{Attribute, Data, DataEnum, DeriveInput, Ident, LitStr, Path};
use super::event_parse::{EventEnumDecl, EventEnumEntry, EventKind}; use super::event_parse::{EventEnumDecl, EventEnumEntry, EventKind};
use crate::util::m_prefix_name_to_type_name; use crate::util::m_prefix_name_to_type_name;
@ -49,7 +49,8 @@ pub fn expand_event_enums(input: &EventEnumDecl) -> syn::Result<TokenStream> {
let kind = input.kind; let kind = input.kind;
let attrs = &input.attrs; let attrs = &input.attrs;
let events: Vec<_> = input.events.iter().map(|entry| entry.ev_type.clone()).collect(); let events: Vec<_> =
input.events.iter().map(|entry| (entry.ev_type.clone(), entry.ev_path.clone())).collect();
let variants: Vec<_> = let variants: Vec<_> =
input.events.iter().map(EventEnumEntry::to_variant).collect::<syn::Result<_>>()?; input.events.iter().map(EventEnumEntry::to_variant).collect::<syn::Result<_>>()?;
@ -110,7 +111,7 @@ pub fn expand_event_enums(input: &EventEnumDecl) -> syn::Result<TokenStream> {
fn expand_event_enum( fn expand_event_enum(
kind: EventKind, kind: EventKind,
var: EventEnumVariation, var: EventEnumVariation,
events: &[LitStr], events: &[(LitStr, Path)],
attrs: &[Attribute], attrs: &[Attribute],
variants: &[EventEnumVariant], variants: &[EventEnumVariant],
ruma_common: &TokenStream, ruma_common: &TokenStream,
@ -120,7 +121,8 @@ fn expand_event_enum(
let variant_decls = variants.iter().map(|v| v.decl()); let variant_decls = variants.iter().map(|v| v.decl());
let content: Vec<_> = let content: Vec<_> =
events.iter().map(|event| to_event_path(event, kind, var, ruma_common)).collect(); events.iter().map(|(name, path)| to_event_path(name, path, kind, var)).collect();
let event_types: Vec<_> = events.iter().map(|(name, _)| name).collect();
let custom_ty = format_ident!("Custom{}Content", kind); let custom_ty = format_ident!("Custom{}Content", kind);
@ -131,11 +133,11 @@ fn expand_event_enum(
Ok(quote! { Ok(quote! {
#( #attrs )* #( #attrs )*
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant, unused_qualifications)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum #ident { pub enum #ident {
#( #(
#[doc = #events] #[doc = #event_types]
#variant_decls(#content), #variant_decls(#content),
)* )*
/// An event not defined by the Matrix specification /// An event not defined by the Matrix specification
@ -154,7 +156,7 @@ fn expand_event_enum(
fn expand_deserialize_impl( fn expand_deserialize_impl(
kind: EventKind, kind: EventKind,
var: EventEnumVariation, var: EventEnumVariation,
events: &[LitStr], events: &[(LitStr, Path)],
variants: &[EventEnumVariant], variants: &[EventEnumVariant],
ruma_common: &TokenStream, ruma_common: &TokenStream,
) -> syn::Result<TokenStream> { ) -> syn::Result<TokenStream> {
@ -168,9 +170,11 @@ fn expand_deserialize_impl(
quote! { #(#attrs)* } quote! { #(#attrs)* }
}); });
let self_variants = variants.iter().map(|v| v.ctor(quote! { Self })); let self_variants = variants.iter().map(|v| v.ctor(quote! { Self }));
let content = events.iter().map(|event| to_event_path(event, kind, var, ruma_common)); let content = events.iter().map(|(name, path)| to_event_path(name, path, kind, var));
let event_types: Vec<_> = events.iter().map(|(name, _)| name).collect();
Ok(quote! { Ok(quote! {
#[allow(unused_qualifications)]
impl<'de> #serde::de::Deserialize<'de> for #ident { impl<'de> #serde::de::Deserialize<'de> for #ident {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
@ -184,7 +188,7 @@ fn expand_deserialize_impl(
match &*ev_type { match &*ev_type {
#( #(
#variant_attrs #events => { #variant_attrs #event_types => {
let event = #serde_json::from_str::<#content>(json.get()) let event = #serde_json::from_str::<#content>(json.get())
.map_err(D::Error::custom)?; .map_err(D::Error::custom)?;
Ok(#self_variants(event)) Ok(#self_variants(event))
@ -210,6 +214,7 @@ fn expand_from_impl(
let attrs = &variant.attrs; let attrs = &variant.attrs;
quote! { quote! {
#[allow(unused_qualifications)]
#[automatically_derived] #[automatically_derived]
#(#attrs)* #(#attrs)*
impl ::std::convert::From<#content> for #ty { impl ::std::convert::From<#content> for #ty {
@ -288,7 +293,7 @@ fn expand_into_full_event(
/// Create a content enum from `EventEnumInput`. /// Create a content enum from `EventEnumInput`.
fn expand_content_enum( fn expand_content_enum(
kind: EventKind, kind: EventKind,
event_types: &[LitStr], events: &[(LitStr, Path)],
attrs: &[Attribute], attrs: &[Attribute],
variants: &[EventEnumVariant], variants: &[EventEnumVariant],
ruma_common: &TokenStream, ruma_common: &TokenStream,
@ -301,14 +306,15 @@ fn expand_content_enum(
let event_type_enum = kind.to_event_type_enum(); let event_type_enum = kind.to_event_type_enum();
let content: Vec<_> = let content: Vec<_> =
event_types.iter().map(|ev| to_event_content_path(kind, ev, None, ruma_common)).collect(); events.iter().map(|(name, path)| to_event_content_path(kind, name, path, None)).collect();
let event_type_match_arms = event_types.iter().map(|s| { let event_type_match_arms = events.iter().map(|(s, _)| {
if let Some(prefix) = s.value().strip_suffix(".*") { if let Some(prefix) = s.value().strip_suffix(".*") {
quote! { _s if _s.starts_with(#prefix) } quote! { _s if _s.starts_with(#prefix) }
} else { } else {
quote! { #s } quote! { #s }
} }
}); });
let event_types: Vec<_> = events.iter().map(|(name, _)| name).collect();
let variant_decls = variants.iter().map(|v| v.decl()).collect::<Vec<_>>(); let variant_decls = variants.iter().map(|v| v.decl()).collect::<Vec<_>>();
let variant_attrs = variants.iter().map(|v| { let variant_attrs = variants.iter().map(|v| {
@ -561,11 +567,10 @@ fn expand_accessor_methods(
fn to_event_path( fn to_event_path(
name: &LitStr, name: &LitStr,
path: &Path,
kind: EventKind, kind: EventKind,
var: EventEnumVariation, var: EventEnumVariation,
ruma_common: &TokenStream,
) -> TokenStream { ) -> TokenStream {
let path = event_module_path(name);
let event = m_prefix_name_to_type_name(name).unwrap(); let event = m_prefix_name_to_type_name(name).unwrap();
let event_name = if kind == EventKind::ToDevice { let event_name = if kind == EventKind::ToDevice {
assert_eq!(var, EventEnumVariation::None); assert_eq!(var, EventEnumVariation::None);
@ -573,16 +578,15 @@ fn to_event_path(
} else { } else {
format_ident!("{}{}Event", var, event) format_ident!("{}{}Event", var, event)
}; };
quote! { #ruma_common::events::#( #path )::*::#event_name } quote! { #path::#event_name }
} }
fn to_event_content_path( fn to_event_content_path(
kind: EventKind, kind: EventKind,
name: &LitStr, name: &LitStr,
path: &Path,
prefix: Option<&str>, prefix: Option<&str>,
ruma_common: &TokenStream,
) -> TokenStream { ) -> TokenStream {
let path = event_module_path(name);
let event = m_prefix_name_to_type_name(name).unwrap(); let event = m_prefix_name_to_type_name(name).unwrap();
let content_str = match kind { let content_str = match kind {
EventKind::ToDevice => { EventKind::ToDevice => {
@ -592,21 +596,10 @@ fn to_event_content_path(
}; };
quote! { quote! {
#ruma_common::events::#( #path )::*::#content_str #path::#content_str
} }
} }
fn event_module_path(name: &LitStr) -> Vec<Ident> {
let value = name.value();
let value = value.strip_prefix("m.").unwrap();
value
.strip_suffix(".*")
.unwrap_or(value)
.split('.')
.map(|s| Ident::new(s, name.span()))
.collect()
}
fn field_return_type(name: &str, ruma_common: &TokenStream) -> TokenStream { fn field_return_type(name: &str, ruma_common: &TokenStream) -> TokenStream {
match name { match name {
"origin_server_ts" => quote! { #ruma_common::MilliSecondsSinceUnixEpoch }, "origin_server_ts" => quote! { #ruma_common::MilliSecondsSinceUnixEpoch },

View File

@ -7,7 +7,7 @@ use quote::{format_ident, IdentFragment};
use syn::{ use syn::{
braced, braced,
parse::{self, Parse, ParseStream}, parse::{self, Parse, ParseStream},
Attribute, Ident, LitStr, Token, Attribute, Ident, LitStr, Path, Token,
}; };
/// Custom keywords for the `event_enum!` macro /// Custom keywords for the `event_enum!` macro
@ -231,11 +231,17 @@ pub fn to_kind_variation(ident: &Ident) -> Option<(EventKind, EventKindVariation
pub struct EventEnumEntry { pub struct EventEnumEntry {
pub attrs: Vec<Attribute>, pub attrs: Vec<Attribute>,
pub ev_type: LitStr, pub ev_type: LitStr,
pub ev_path: Path,
} }
impl Parse for EventEnumEntry { impl Parse for EventEnumEntry {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> { fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
Ok(Self { attrs: input.call(Attribute::parse_outer)?, ev_type: input.parse()? }) let attrs = input.call(Attribute::parse_outer)?;
let ev_type: LitStr = input.parse()?;
let _: Token![=>] = input.parse()?;
let ev_path = input.call(Path::parse_mod_style)?;
Ok(Self { attrs, ev_type, ev_path })
} }
} }

View File

@ -1,6 +1,6 @@
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::quote; use quote::quote;
use syn::{Ident, LitStr}; use syn::{parse_quote, Ident, LitStr};
use super::event_parse::{EventEnumEntry, EventEnumInput, EventKind}; use super::event_parse::{EventEnumEntry, EventEnumInput, EventKind};
@ -38,6 +38,7 @@ pub fn expand_event_type_enum(
let presence = vec![EventEnumEntry { let presence = vec![EventEnumEntry {
attrs: vec![], attrs: vec![],
ev_type: LitStr::new("m.presence", Span::call_site()), ev_type: LitStr::new("m.presence", Span::call_site()),
ev_path: parse_quote! { #ruma_common::events::presence },
}]; }];
let mut all = input.enums.iter().map(|e| &e.events).collect::<Vec<_>>(); let mut all = input.enums.iter().map(|e| &e.events).collect::<Vec<_>>();
all.push(&presence); all.push(&presence);