diff --git a/crates/ruma-macros/src/events/event_enum.rs b/crates/ruma-macros/src/events/event_enum.rs index 5dc1768d..74838254 100644 --- a/crates/ruma-macros/src/events/event_enum.rs +++ b/crates/ruma-macros/src/events/event_enum.rs @@ -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, Path}; +use syn::{Attribute, Data, DataEnum, DeriveInput, Ident, LitStr}; use super::event_parse::{EventEnumDecl, EventEnumEntry, EventKind}; use crate::util::m_prefix_name_to_type_name; @@ -114,14 +114,7 @@ fn expand_event_enum( let ident = kind.to_event_enum_ident(var.into())?; let variant_decls = variants.iter().map(|v| v.decl()); - let event_ty: Vec<_> = events - .iter() - .map(|event| { - event - .stable_name() - .map(|stable_name| to_event_path(stable_name, &event.ev_path, kind, var)) - }) - .collect::>()?; + let event_ty: Vec<_> = events.iter().map(|event| event.to_event_path(kind, var)).collect(); let custom_content_ty = format_ident!("Custom{}Content", kind); @@ -175,7 +168,7 @@ fn expand_deserialize_impl( quote! { #(#attrs)* } }; let self_variant = variant.ctor(quote! { Self }); - let content = to_event_path(event.stable_name()?, &event.ev_path, kind, var); + let content = event.to_event_path(kind, var); let ev_types = event.aliases.iter().chain([&event.ev_type]); Ok(quote! { @@ -314,13 +307,8 @@ fn expand_content_enum( let event_type_enum = kind.to_event_type_enum(); - let content: Vec<_> = events - .iter() - .map(|event| { - let stable_name = event.stable_name()?; - Ok(to_event_content_path(kind, stable_name, &event.ev_path, None)) - }) - .collect::>()?; + let content: Vec<_> = + events.iter().map(|event| event.to_event_content_path(kind, None)).collect(); let variant_decls = variants.iter().map(|v| v.decl()).collect::>(); let variant_arms = variants.iter().map(|v| v.match_arm(quote! { Self })).collect::>(); @@ -389,13 +377,8 @@ fn expand_full_content_enum( let event_type_enum = kind.to_event_type_enum(); - let content: Vec<_> = events - .iter() - .map(|event| { - let stable_name = event.stable_name()?; - Ok(to_event_content_path(kind, stable_name, &event.ev_path, None)) - }) - .collect::>()?; + let content: Vec<_> = + events.iter().map(|event| event.to_event_content_path(kind, None)).collect(); let variant_decls = variants.iter().map(|v| v.decl()).collect::>(); let variant_arms = variants.iter().map(|v| v.match_arm(quote! { Self })).collect::>(); @@ -669,41 +652,6 @@ fn expand_accessor_methods( }) } -fn to_event_path( - name: &LitStr, - path: &Path, - kind: EventKind, - var: EventEnumVariation, -) -> TokenStream { - let event = m_prefix_name_to_type_name(name).unwrap(); - let event_name = if kind == EventKind::ToDevice { - assert_eq!(var, EventEnumVariation::None); - format_ident!("ToDevice{}Event", event) - } else { - format_ident!("{}{}Event", var, event) - }; - quote! { #path::#event_name } -} - -fn to_event_content_path( - kind: EventKind, - name: &LitStr, - path: &Path, - prefix: Option<&str>, -) -> TokenStream { - let event = m_prefix_name_to_type_name(name).unwrap(); - let content_str = match kind { - EventKind::ToDevice => { - format_ident!("ToDevice{}{}EventContent", prefix.unwrap_or(""), event) - } - _ => format_ident!("{}{}EventContent", prefix.unwrap_or(""), event), - }; - - quote! { - #path::#content_str - } -} - fn field_return_type(name: &str, ruma_common: &TokenStream) -> TokenStream { match name { "origin_server_ts" => quote! { #ruma_common::MilliSecondsSinceUnixEpoch }, @@ -758,7 +706,7 @@ impl EventEnumEntry { pub(crate) fn to_variant(&self) -> syn::Result { let attrs = self.attrs.clone(); - let ident = m_prefix_name_to_type_name(self.stable_name()?)?; + let ident = self.ident()?; Ok(EventEnumVariant { attrs, ident }) } @@ -772,7 +720,8 @@ impl EventEnumEntry { Span::call_site(), format!( "A matrix event must declare a well-known type that starts with `m.` \ - either as the main type or as an alias, found `{}`", + either as the main type or as an alias, or must declare the ident that \ + should be used if it is only an unstable type, found main type `{}`", self.ev_type.value() ), ) @@ -780,14 +729,49 @@ impl EventEnumEntry { } } - pub(crate) fn docs(&self) -> syn::Result { - let stable_name = self.stable_name()?; + pub(crate) fn ident(&self) -> syn::Result { + if let Some(ident) = self.ident.clone() { + Ok(ident) + } else { + m_prefix_name_to_type_name(self.stable_name()?) + } + } - let mut doc = quote! { - #[doc = #stable_name] + fn to_event_path(&self, kind: EventKind, var: EventEnumVariation) -> TokenStream { + let path = &self.ev_path; + let ident = self.ident().unwrap(); + let event_name = if kind == EventKind::ToDevice { + assert_eq!(var, EventEnumVariation::None); + format_ident!("ToDevice{ident}Event") + } else { + format_ident!("{}{ident}Event", var) + }; + quote! { #path::#event_name } + } + + fn to_event_content_path(&self, kind: EventKind, prefix: Option<&str>) -> TokenStream { + let path = &self.ev_path; + let ident = self.ident().unwrap(); + let content_str = match kind { + EventKind::ToDevice => { + format_ident!("ToDevice{}{ident}EventContent", prefix.unwrap_or("")) + } + _ => format_ident!("{}{ident}EventContent", prefix.unwrap_or("")), }; - if self.ev_type != *stable_name { + quote! { + #path::#content_str + } + } + + pub(crate) fn docs(&self) -> syn::Result { + let main_name = self.stable_name().unwrap_or(&self.ev_type); + + let mut doc = quote! { + #[doc = #main_name] + }; + + if self.ev_type != *main_name { let unstable_name = format!("This variant uses the unstable type `{}`.", self.ev_type.value()); diff --git a/crates/ruma-macros/src/events/event_parse.rs b/crates/ruma-macros/src/events/event_parse.rs index f3593321..c067e7ea 100644 --- a/crates/ruma-macros/src/events/event_parse.rs +++ b/crates/ruma-macros/src/events/event_parse.rs @@ -16,6 +16,7 @@ mod kw { syn::custom_keyword!(kind); syn::custom_keyword!(events); syn::custom_keyword!(alias); + syn::custom_keyword!(ident); } // If the variants of this enum change `to_event_path` needs to be updated as well. @@ -228,6 +229,7 @@ pub struct EventEnumEntry { pub aliases: Vec, pub ev_type: LitStr, pub ev_path: Path, + pub ident: Option, } impl Parse for EventEnumEntry { @@ -242,24 +244,38 @@ impl Parse for EventEnumEntry { let has_suffix = ev_type.value().ends_with(".*"); let mut aliases = Vec::with_capacity(ruma_enum_attrs.len()); - for attr_list in ruma_enum_attrs { - for alias_attr in attr_list - .parse_args_with(Punctuated::::parse_terminated)? - { - let alias = alias_attr.into_inner(); + let mut ident = None; - if alias.value().ends_with(".*") == has_suffix { - aliases.push(alias); - } else { - return Err(syn::Error::new_spanned( - &attr_list, - "aliases should have the same `.*` suffix, or lack thereof, as the main event type", - )); + for attr_list in ruma_enum_attrs { + for attr in attr_list + .parse_args_with(Punctuated::::parse_terminated)? + { + match attr { + EventEnumAttr::Alias(alias) => { + if alias.value().ends_with(".*") == has_suffix { + aliases.push(alias); + } else { + return Err(syn::Error::new_spanned( + &attr_list, + "aliases should have the same `.*` suffix, or lack thereof, as the main event type", + )); + } + } + EventEnumAttr::Ident(i) => { + if ident.is_some() { + return Err(syn::Error::new_spanned( + &attr_list, + "multiple `ident` attributes found, there can be only one", + )); + } + + ident = Some(i); + } } } } - Ok(Self { attrs, aliases, ev_type, ev_path }) + Ok(Self { attrs, aliases, ev_type, ev_path, ident }) } } @@ -304,19 +320,27 @@ impl Parse for EventEnumInput { } } -pub struct EventEnumAliasAttr(LitStr); - -impl EventEnumAliasAttr { - pub fn into_inner(self) -> LitStr { - self.0 - } +pub enum EventEnumAttr { + Alias(LitStr), + Ident(Ident), } -impl Parse for EventEnumAliasAttr { +impl Parse for EventEnumAttr { fn parse(input: ParseStream<'_>) -> syn::Result { - let _: kw::alias = input.parse()?; - let _: Token![=] = input.parse()?; - let s: LitStr = input.parse()?; - Ok(Self(s)) + let lookahead = input.lookahead1(); + + if lookahead.peek(kw::alias) { + let _: kw::alias = input.parse()?; + let _: Token![=] = input.parse()?; + let s: LitStr = input.parse()?; + Ok(Self::Alias(s)) + } else if lookahead.peek(kw::ident) { + let _: kw::ident = input.parse()?; + let _: Token![=] = input.parse()?; + let i: Ident = input.parse()?; + Ok(Self::Ident(i)) + } else { + Err(lookahead.error()) + } } } diff --git a/crates/ruma-macros/src/events/event_type.rs b/crates/ruma-macros/src/events/event_type.rs index 810bd131..3de8cbdf 100644 --- a/crates/ruma-macros/src/events/event_type.rs +++ b/crates/ruma-macros/src/events/event_type.rs @@ -40,6 +40,7 @@ pub fn expand_event_type_enum( aliases: vec![], ev_type: LitStr::new("m.presence", Span::call_site()), ev_path: parse_quote! { #ruma_common::events::presence }, + ident: None, }]; let mut all = input.enums.iter().map(|e| &e.events).collect::>(); all.push(&presence);