events: Allow to declare events without a stable prefix

This commit is contained in:
Kévin Commaille 2023-07-06 14:38:57 +02:00 committed by Kévin Commaille
parent c0b8cd4d46
commit e780633cce
3 changed files with 99 additions and 90 deletions

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, 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::<syn::Result<_>>()?;
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::<syn::Result<_>>()?;
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::<Vec<_>>();
let variant_arms = variants.iter().map(|v| v.match_arm(quote! { Self })).collect::<Vec<_>>();
@ -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::<syn::Result<_>>()?;
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::<Vec<_>>();
let variant_arms = variants.iter().map(|v| v.match_arm(quote! { Self })).collect::<Vec<_>>();
@ -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<EventEnumVariant> {
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<TokenStream> {
let stable_name = self.stable_name()?;
pub(crate) fn ident(&self) -> syn::Result<Ident> {
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<TokenStream> {
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());

View File

@ -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<LitStr>,
pub ev_type: LitStr,
pub ev_path: Path,
pub ident: Option<Ident>,
}
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::<EventEnumAliasAttr, Token![,]>::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::<EventEnumAttr, Token![,]>::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<Self> {
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())
}
}
}

View File

@ -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::<Vec<_>>();
all.push(&presence);