macros: Simplify *EventType generation

This commit is contained in:
Jonas Platte 2022-03-15 16:07:09 +01:00
parent 1b24a76967
commit 6f6e7ca68e
No known key found for this signature in database
GPG Key ID: BBA95679259D342F

View File

@ -1,5 +1,5 @@
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote}; use quote::quote;
use syn::{Ident, LitStr}; use syn::{Ident, LitStr};
use super::event_parse::{EventEnumEntry, EventEnumInput, EventKind}; use super::event_parse::{EventEnumEntry, EventEnumInput, EventKind};
@ -41,89 +41,49 @@ pub fn expand_event_type_enum(
}]; }];
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);
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_common);
let (room_event_types, room_str_ev_types) = generate_variants(&room)?; let mut res = TokenStream::new();
let room = generate_enum(
format_ident!("RoomEventType"),
room_str_ev_types,
room_event_types,
&ruma_common,
);
let (state_event_types, state_str_ev_types) = generate_variants(&state)?; res.extend(generate_enum("EventType", &all, &ruma_common)?);
let state = generate_enum( res.extend(generate_enum("RoomEventType", &room, &ruma_common)?);
format_ident!("StateEventType"), res.extend(generate_enum("StateEventType", &state, &ruma_common)?);
state_str_ev_types, res.extend(generate_enum("MessageLikeEventType", &message, &ruma_common)?);
state_event_types, res.extend(generate_enum("EphemeralRoomEventType", &ephemeral, &ruma_common)?);
&ruma_common, res.extend(generate_enum("RoomAccountDataEventType", &room_account, &ruma_common)?);
); res.extend(generate_enum("GlobalAccountDataEventType", &global_account, &ruma_common)?);
res.extend(generate_enum("ToDeviceEventType", &to_device, &ruma_common)?);
let (message_event_types, message_str_ev_types) = generate_variants(&message)?; Ok(res)
let message = generate_enum(
format_ident!("MessageLikeEventType"),
message_str_ev_types,
message_event_types,
&ruma_common,
);
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_common,
);
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_common,
);
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_common,
);
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_common,
);
Ok(quote! {
#all
#room
#state
#message
#ephemeral
#room_account
#global_account
#to_device
})
} }
fn generate_enum( fn generate_enum(
ident: Ident, ident: &str,
ev_type_strings: Vec<&LitStr>, input: &[&Vec<EventEnumEntry>],
variants: Vec<TokenStream>,
ruma_common: &TokenStream, ruma_common: &TokenStream,
) -> TokenStream { ) -> syn::Result<TokenStream> {
let str_doc = format!("Creates a string slice from this `{}`.", ident); let str_doc = format!("Creates a string slice from this `{}`.", ident);
let byte_doc = format!("Creates a byte 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); let enum_doc = format!("The type of `{}` this is.", ident.strip_suffix("Type").unwrap());
quote! {
let ident = Ident::new(ident, Span::call_site());
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);
let variants =
deduped.iter().map(|e| Ok(e.to_variant()?.decl())).collect::<syn::Result<Vec<_>>>()?;
Ok(quote! {
#[doc = #enum_doc] #[doc = #enum_doc]
/// ///
/// This type can hold an arbitrary string. To check for events that are not available as a /// This type can hold an arbitrary string. To check for events that are not available as a
@ -132,8 +92,8 @@ fn generate_enum(
#[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 = #ev_type_strings] #[doc = #event_types]
#[ruma_enum(rename = #ev_type_strings)] #[ruma_enum(rename = #event_types)]
#variants, #variants,
)* )*
#[doc(hidden)] #[doc(hidden)]
@ -151,27 +111,5 @@ fn generate_enum(
self.as_str().as_bytes() self.as_str().as_bytes()
} }
} }
} })
}
fn generate_variants<'a>(
input: &'a [&Vec<EventEnumEntry>],
) -> syn::Result<(Vec<TokenStream>, 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::<syn::Result<Vec<_>>>()?;
Ok((event_types_variants, event_types))
} }