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

View File

@ -1,15 +1,16 @@
use ruma_common::events;
use ruma_macros::event_enum;
event_enum! {
/// Any global account data event.
enum GlobalAccountData {
"m.direct",
"m.direct" => events::direct,
#[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
"m.push_rules.*",
"m.push_rules.*" => events::push_rules,
#[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;
event_enum! {
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`
--> 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",
| ^^^^^^^^^^^^^^ could not find `not` in `events`
6 | "m.not.a.path" => events::not::a::path,
| ^^^ could not find `not` in `events`

View File

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

View File

@ -7,7 +7,7 @@ use quote::{format_ident, IdentFragment};
use syn::{
braced,
parse::{self, Parse, ParseStream},
Attribute, Ident, LitStr, Token,
Attribute, Ident, LitStr, Path, Token,
};
/// 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 attrs: Vec<Attribute>,
pub ev_type: LitStr,
pub ev_path: Path,
}
impl Parse for EventEnumEntry {
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 quote::quote;
use syn::{Ident, LitStr};
use syn::{parse_quote, Ident, LitStr};
use super::event_parse::{EventEnumEntry, EventEnumInput, EventKind};
@ -38,6 +38,7 @@ pub fn expand_event_type_enum(
let presence = vec![EventEnumEntry {
attrs: vec![],
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<_>>();
all.push(&presence);