Jonas Platte 31331f3165
Bring back ruma-events
Co-authored-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-08-28 10:23:54 +02:00

899 lines
31 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Implementation of event enum and event content enum macros.
use std::fmt;
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote, IdentFragment, ToTokens};
use syn::{Attribute, Data, DataEnum, DeriveInput, Ident, LitStr};
use super::event_parse::{EventEnumDecl, EventEnumEntry, EventKind};
use crate::util::m_prefix_name_to_type_name;
/// Custom keywords for the `event_enum!` macro
mod kw {
syn::custom_keyword!(kind);
syn::custom_keyword!(events);
}
pub(crate) fn is_non_stripped_room_event(kind: EventKind, var: EventEnumVariation) -> bool {
matches!(kind, EventKind::MessageLike | EventKind::State)
&& matches!(var, EventEnumVariation::None | EventEnumVariation::Sync)
}
type EventKindFn = fn(EventKind, EventEnumVariation) -> bool;
/// This const is used to generate the accessor methods for the `Any*Event` enums.
///
/// DO NOT alter the field names unless the structs in `ruma_events::event_kinds` have
/// changed.
const EVENT_FIELDS: &[(&str, EventKindFn)] = &[
("origin_server_ts", is_non_stripped_room_event),
("room_id", |kind, var| {
matches!(kind, EventKind::MessageLike | EventKind::State | EventKind::Ephemeral)
&& matches!(var, EventEnumVariation::None)
}),
("event_id", is_non_stripped_room_event),
("sender", |kind, var| {
matches!(kind, EventKind::MessageLike | EventKind::State | EventKind::ToDevice)
&& var != EventEnumVariation::Initial
}),
];
/// Create a content enum from `EventEnumInput`.
pub fn expand_event_enums(input: &EventEnumDecl) -> syn::Result<TokenStream> {
use EventEnumVariation as V;
let ruma_events = crate::import_ruma_events();
let mut res = TokenStream::new();
let kind = input.kind;
let attrs = &input.attrs;
let docs: Vec<_> = input.events.iter().map(EventEnumEntry::docs).collect::<syn::Result<_>>()?;
let variants: Vec<_> =
input.events.iter().map(EventEnumEntry::to_variant).collect::<syn::Result<_>>()?;
let events = &input.events;
let docs = &docs;
let variants = &variants;
let ruma_events = &ruma_events;
res.extend(expand_content_enum(kind, events, docs, attrs, variants, ruma_events));
res.extend(
expand_event_enum(kind, V::None, events, docs, attrs, variants, ruma_events)
.unwrap_or_else(syn::Error::into_compile_error),
);
if matches!(kind, EventKind::MessageLike | EventKind::State) {
res.extend(
expand_event_enum(kind, V::Sync, events, docs, attrs, variants, ruma_events)
.unwrap_or_else(syn::Error::into_compile_error),
);
res.extend(
expand_from_full_event(kind, V::None, variants)
.unwrap_or_else(syn::Error::into_compile_error),
);
res.extend(
expand_into_full_event(kind, V::Sync, variants, ruma_events)
.unwrap_or_else(syn::Error::into_compile_error),
);
}
if matches!(kind, EventKind::Ephemeral) {
res.extend(
expand_event_enum(kind, V::Sync, events, docs, attrs, variants, ruma_events)
.unwrap_or_else(syn::Error::into_compile_error),
);
}
if matches!(kind, EventKind::State) {
res.extend(expand_full_content_enum(kind, events, docs, attrs, variants, ruma_events));
res.extend(
expand_event_enum(kind, V::Stripped, events, docs, attrs, variants, ruma_events)
.unwrap_or_else(syn::Error::into_compile_error),
);
res.extend(
expand_event_enum(kind, V::Initial, events, docs, attrs, variants, ruma_events)
.unwrap_or_else(syn::Error::into_compile_error),
);
}
Ok(res)
}
fn expand_event_enum(
kind: EventKind,
var: EventEnumVariation,
events: &[EventEnumEntry],
docs: &[TokenStream],
attrs: &[Attribute],
variants: &[EventEnumVariant],
ruma_events: &TokenStream,
) -> syn::Result<TokenStream> {
let event_struct = kind.to_event_ident(var.into())?;
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.to_event_path(kind, var)).collect();
let custom_content_ty = format_ident!("Custom{}Content", kind);
let deserialize_impl = expand_deserialize_impl(kind, var, events, ruma_events)?;
let field_accessor_impl =
expand_accessor_methods(kind, var, variants, &event_struct, ruma_events)?;
let from_impl = expand_from_impl(&ident, &event_ty, variants);
Ok(quote! {
#( #attrs )*
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant, unused_qualifications)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum #ident {
#(
#docs
#variant_decls(#event_ty),
)*
/// An event not defined by the Matrix specification
#[doc(hidden)]
_Custom(
#ruma_events::#event_struct<
#ruma_events::_custom::#custom_content_ty
>,
),
}
#deserialize_impl
#field_accessor_impl
#from_impl
})
}
fn expand_deserialize_impl(
kind: EventKind,
var: EventEnumVariation,
events: &[EventEnumEntry],
ruma_events: &TokenStream,
) -> syn::Result<TokenStream> {
let ruma_common = quote! { #ruma_events::exports::ruma_common };
let serde = quote! { #ruma_events::exports::serde };
let serde_json = quote! { #ruma_events::exports::serde_json };
let ident = kind.to_event_enum_ident(var.into())?;
let match_arms: TokenStream = events
.iter()
.map(|event| {
let variant = event.to_variant()?;
let variant_attrs = {
let attrs = &variant.attrs;
quote! { #(#attrs)* }
};
let self_variant = variant.ctor(quote! { Self });
let content = event.to_event_path(kind, var);
let ev_types = event.aliases.iter().chain([&event.ev_type]);
Ok(quote! {
#variant_attrs #(#ev_types)|* => {
let event = #serde_json::from_str::<#content>(json.get())
.map_err(D::Error::custom)?;
Ok(#self_variant(event))
},
})
})
.collect::<syn::Result<_>>()?;
Ok(quote! {
#[allow(unused_qualifications)]
impl<'de> #serde::de::Deserialize<'de> for #ident {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: #serde::de::Deserializer<'de>,
{
use #serde::de::Error as _;
let json = Box::<#serde_json::value::RawValue>::deserialize(deserializer)?;
let #ruma_events::EventTypeDeHelper { ev_type, .. } =
#ruma_common::serde::from_raw_json_value(&json)?;
match &*ev_type {
#match_arms
_ => {
let event = #serde_json::from_str(json.get()).map_err(D::Error::custom)?;
Ok(Self::_Custom(event))
},
}
}
}
})
}
fn expand_from_impl(
ty: &Ident,
event_ty: &[TokenStream],
variants: &[EventEnumVariant],
) -> TokenStream {
let from_impls = event_ty.iter().zip(variants).map(|(event_ty, variant)| {
let ident = &variant.ident;
let attrs = &variant.attrs;
quote! {
#[allow(unused_qualifications)]
#[automatically_derived]
#(#attrs)*
impl ::std::convert::From<#event_ty> for #ty {
fn from(c: #event_ty) -> Self {
Self::#ident(c)
}
}
}
});
quote! { #( #from_impls )* }
}
fn expand_from_full_event(
kind: EventKind,
var: EventEnumVariation,
variants: &[EventEnumVariant],
) -> syn::Result<TokenStream> {
let ident = kind.to_event_enum_ident(var.into())?;
let sync = kind.to_event_enum_ident(var.to_sync().into())?;
let ident_variants = variants.iter().map(|v| v.match_arm(&ident));
let self_variants = variants.iter().map(|v| v.ctor(quote! { Self }));
Ok(quote! {
#[automatically_derived]
impl ::std::convert::From<#ident> for #sync {
fn from(event: #ident) -> Self {
match event {
#(
#ident_variants(event) => {
#self_variants(::std::convert::From::from(event))
},
)*
#ident::_Custom(event) => {
Self::_Custom(::std::convert::From::from(event))
},
}
}
}
})
}
fn expand_into_full_event(
kind: EventKind,
var: EventEnumVariation,
variants: &[EventEnumVariant],
ruma_events: &TokenStream,
) -> syn::Result<TokenStream> {
let ruma_common = quote! { #ruma_events::exports::ruma_common };
let ident = kind.to_event_enum_ident(var.into())?;
let full = kind.to_event_enum_ident(var.to_full().into())?;
let self_variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
let full_variants = variants.iter().map(|v| v.ctor(&full));
Ok(quote! {
#[automatically_derived]
impl #ident {
/// Convert this sync event into a full event (one with a `room_id` field).
pub fn into_full_event(self, room_id: #ruma_common::OwnedRoomId) -> #full {
match self {
#(
#self_variants(event) => {
#full_variants(event.into_full_event(room_id))
},
)*
Self::_Custom(event) => {
#full::_Custom(event.into_full_event(room_id))
},
}
}
}
})
}
/// Create a content enum from `EventEnumInput`.
fn expand_content_enum(
kind: EventKind,
events: &[EventEnumEntry],
docs: &[TokenStream],
attrs: &[Attribute],
variants: &[EventEnumVariant],
ruma_events: &TokenStream,
) -> syn::Result<TokenStream> {
let serde = quote! { #ruma_events::exports::serde };
let ident = kind.to_content_enum();
let event_type_enum = kind.to_event_type_enum();
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<_>>();
let sub_trait_name = format_ident!("{kind}Content");
let state_event_content_impl = (kind == EventKind::State).then(|| {
quote! {
type StateKey = String;
}
});
let from_impl = expand_from_impl(&ident, &content, variants);
let serialize_custom_event_error_path =
quote! { #ruma_events::serialize_custom_event_error }.to_string();
Ok(quote! {
#( #attrs )*
#[derive(Clone, Debug, #serde::Serialize)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum #ident {
#(
#docs
#variant_decls(#content),
)*
#[doc(hidden)]
#[serde(serialize_with = #serialize_custom_event_error_path)]
_Custom {
event_type: crate::PrivOwnedStr,
},
}
#[automatically_derived]
impl #ruma_events::EventContent for #ident {
type EventType = #ruma_events::#event_type_enum;
fn event_type(&self) -> Self::EventType {
match self {
#( #variant_arms(content) => content.event_type(), )*
Self::_Custom { event_type } => ::std::convert::From::from(&event_type.0[..]),
}
}
}
#[automatically_derived]
impl #ruma_events::#sub_trait_name for #ident {
#state_event_content_impl
}
#from_impl
})
}
/// Create a full content enum from `EventEnumInput`.
fn expand_full_content_enum(
kind: EventKind,
events: &[EventEnumEntry],
docs: &[TokenStream],
attrs: &[Attribute],
variants: &[EventEnumVariant],
ruma_events: &TokenStream,
) -> syn::Result<TokenStream> {
let ident = kind.to_full_content_enum();
let event_type_enum = kind.to_event_type_enum();
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<_>>();
Ok(quote! {
#( #attrs )*
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum #ident {
#(
#docs
#variant_decls(#ruma_events::FullStateEventContent<#content>),
)*
#[doc(hidden)]
_Custom {
event_type: crate::PrivOwnedStr,
redacted: bool,
},
}
impl #ident {
/// Get the events type, like `m.room.create`.
pub fn event_type(&self) -> #ruma_events::#event_type_enum {
match self {
#( #variant_arms(content) => content.event_type(), )*
Self::_Custom { event_type, .. } => ::std::convert::From::from(&event_type.0[..]),
}
}
}
})
}
fn expand_accessor_methods(
kind: EventKind,
var: EventEnumVariation,
variants: &[EventEnumVariant],
event_struct: &Ident,
ruma_events: &TokenStream,
) -> syn::Result<TokenStream> {
let ruma_common = quote! { #ruma_events::exports::ruma_common };
let ident = kind.to_event_enum_ident(var.into())?;
let event_type_enum = format_ident!("{}Type", kind);
let self_variants: Vec<_> = variants.iter().map(|v| v.match_arm(quote! { Self })).collect();
let maybe_redacted =
kind.is_timeline() && matches!(var, EventEnumVariation::None | EventEnumVariation::Sync);
let event_type_match_arms = if maybe_redacted {
quote! {
#( #self_variants(event) => event.event_type(), )*
Self::_Custom(event) => event.event_type(),
}
} else {
quote! {
#( #self_variants(event) =>
#ruma_events::EventContent::event_type(&event.content), )*
Self::_Custom(event) => ::std::convert::From::from(
#ruma_events::EventContent::event_type(&event.content),
),
}
};
let content_enum = kind.to_content_enum();
let content_variants: Vec<_> = variants.iter().map(|v| v.ctor(&content_enum)).collect();
let content_accessor = if maybe_redacted {
let mut accessors = quote! {
/// Returns the content for this event if it is not redacted, or `None` if it is.
pub fn original_content(&self) -> Option<#content_enum> {
match self {
#(
#self_variants(event) => {
event.as_original().map(|ev| #content_variants(ev.content.clone()))
}
)*
Self::_Custom(event) => event.as_original().map(|ev| {
#content_enum::_Custom {
event_type: crate::PrivOwnedStr(
::std::convert::From::from(
::std::string::ToString::to_string(
&#ruma_events::EventContent::event_type(
&ev.content,
),
),
),
),
}
}),
}
}
};
if kind == EventKind::State {
let full_content_enum = kind.to_full_content_enum();
let full_content_variants: Vec<_> =
variants.iter().map(|v| v.ctor(&full_content_enum)).collect();
accessors = quote! {
#accessors
/// Returns the content of this state event.
pub fn content(&self) -> #full_content_enum {
match self {
#(
#self_variants(event) => match event {
#ruma_events::#event_struct::Original(ev) => #full_content_variants(
#ruma_events::FullStateEventContent::Original {
content: ev.content.clone(),
prev_content: ev.unsigned.prev_content.clone()
}
),
#ruma_events::#event_struct::Redacted(ev) => #full_content_variants(
#ruma_events::FullStateEventContent::Redacted(
ev.content.clone()
)
),
}
)*
Self::_Custom(event) => match event {
#ruma_events::#event_struct::Original(ev) => {
#full_content_enum::_Custom {
event_type: crate::PrivOwnedStr(
::std::string::ToString::to_string(
&#ruma_events::EventContent::event_type(
&ev.content,
),
).into_boxed_str(),
),
redacted: false,
}
}
#ruma_events::#event_struct::Redacted(ev) => {
#full_content_enum::_Custom {
event_type: crate::PrivOwnedStr(
::std::string::ToString::to_string(
&#ruma_events::EventContent::event_type(
&ev.content,
),
).into_boxed_str(),
),
redacted: true,
}
}
},
}
}
};
}
accessors
} else if var == EventEnumVariation::Stripped {
// There is no content enum for possibly-redacted content types (yet)
TokenStream::new()
} else {
quote! {
/// Returns the content for this event.
pub fn content(&self) -> #content_enum {
match self {
#( #self_variants(event) => #content_variants(event.content.clone()), )*
Self::_Custom(event) => #content_enum::_Custom {
event_type: crate::PrivOwnedStr(
::std::convert::From::from(
::std::string::ToString::to_string(
&#ruma_events::EventContent::event_type(&event.content)
)
),
),
},
}
}
}
};
let methods = EVENT_FIELDS.iter().map(|(name, has_field)| {
has_field(kind, var).then(|| {
let docs = format!("Returns this event's `{name}` field.");
let ident = Ident::new(name, Span::call_site());
let field_type = field_return_type(name, ruma_events);
let variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
let call_parens = maybe_redacted.then(|| quote! { () });
let ampersand = (*name != "origin_server_ts").then(|| quote! { & });
quote! {
#[doc = #docs]
pub fn #ident(&self) -> #field_type {
match self {
#( #variants(event) => #ampersand event.#ident #call_parens, )*
Self::_Custom(event) => #ampersand event.#ident #call_parens,
}
}
}
})
});
let state_key_accessor = (kind == EventKind::State).then(|| {
let variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
let call_parens = maybe_redacted.then(|| quote! { () });
quote! {
/// Returns this event's `state_key` field.
pub fn state_key(&self) -> &::std::primitive::str {
match self {
#( #variants(event) => &event.state_key #call_parens .as_ref(), )*
Self::_Custom(event) => &event.state_key #call_parens .as_ref(),
}
}
}
});
let relations_accessor = (kind == EventKind::MessageLike).then(|| {
let variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
quote! {
/// Returns this event's `relations` from inside `unsigned`.
pub fn relations(
&self,
) -> #ruma_events::BundledMessageLikeRelations<AnySyncMessageLikeEvent> {
match self {
#(
#variants(event) => event.as_original().map_or_else(
::std::default::Default::default,
|ev| ev.unsigned.relations.clone().map_replace(|r| {
::std::convert::From::from(r.into_maybe_redacted())
}),
),
)*
Self::_Custom(event) => event.as_original().map_or_else(
::std::default::Default::default,
|ev| ev.unsigned.relations.clone().map_replace(|r| {
AnySyncMessageLikeEvent::_Custom(r.into_maybe_redacted())
}),
),
}
}
}
});
let maybe_redacted_accessors = maybe_redacted.then(|| {
let variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
quote! {
/// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
pub fn transaction_id(&self) -> Option<&#ruma_common::TransactionId> {
match self {
#(
#variants(event) => {
event.as_original().and_then(|ev| ev.unsigned.transaction_id.as_deref())
}
)*
Self::_Custom(event) => {
event.as_original().and_then(|ev| ev.unsigned.transaction_id.as_deref())
}
}
}
}
});
Ok(quote! {
#[automatically_derived]
impl #ident {
/// Returns the `type` of this event.
pub fn event_type(&self) -> #ruma_events::#event_type_enum {
match self { #event_type_match_arms }
}
#content_accessor
#( #methods )*
#relations_accessor
#state_key_accessor
#maybe_redacted_accessors
}
})
}
fn field_return_type(name: &str, ruma_events: &TokenStream) -> TokenStream {
let ruma_common = quote! { #ruma_events::exports::ruma_common };
match name {
"origin_server_ts" => quote! { #ruma_common::MilliSecondsSinceUnixEpoch },
"room_id" => quote! { &#ruma_common::RoomId },
"event_id" => quote! { &#ruma_common::EventId },
"sender" => quote! { &#ruma_common::UserId },
_ => panic!("the `ruma_macros::event_enum::EVENT_FIELD` const was changed"),
}
}
pub(crate) struct EventEnumVariant {
pub attrs: Vec<Attribute>,
pub ident: Ident,
}
impl EventEnumVariant {
pub(crate) fn to_tokens<T>(&self, prefix: Option<T>, with_attrs: bool) -> TokenStream
where
T: ToTokens,
{
let mut tokens = TokenStream::new();
if with_attrs {
for attr in &self.attrs {
attr.to_tokens(&mut tokens);
}
}
if let Some(p) = prefix {
tokens.extend(quote! { #p :: });
}
self.ident.to_tokens(&mut tokens);
tokens
}
pub(crate) fn decl(&self) -> TokenStream {
self.to_tokens::<TokenStream>(None, true)
}
pub(crate) fn match_arm(&self, prefix: impl ToTokens) -> TokenStream {
self.to_tokens(Some(prefix), true)
}
pub(crate) fn ctor(&self, prefix: impl ToTokens) -> TokenStream {
self.to_tokens(Some(prefix), false)
}
}
impl EventEnumEntry {
pub(crate) fn has_type_fragment(&self) -> bool {
self.ev_type.value().ends_with(".*")
}
pub(crate) fn to_variant(&self) -> syn::Result<EventEnumVariant> {
let attrs = self.attrs.clone();
let ident = self.ident()?;
Ok(EventEnumVariant { attrs, ident })
}
pub(crate) fn stable_name(&self) -> syn::Result<&LitStr> {
if self.ev_type.value().starts_with("m.") {
Ok(&self.ev_type)
} else {
self.aliases.iter().find(|alias| alias.value().starts_with("m.")).ok_or_else(|| {
syn::Error::new(
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, or must declare the ident that \
should be used if it is only an unstable type, found main type `{}`",
self.ev_type.value()
),
)
})
}
}
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()?)
}
}
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("")),
};
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());
doc.extend(quote! {
#[doc = ""]
#[doc = #unstable_name]
});
}
match self.aliases.len() {
0 => {}
1 => {
let alias = format!(
"This variant can also be deserialized from the `{}` type.",
self.aliases[0].value()
);
doc.extend(quote! {
#[doc = ""]
#[doc = #alias]
});
}
_ => {
let aliases = format!(
"This variant can also be deserialized from the following types: {}.",
self.aliases
.iter()
.map(|alias| format!("`{}`", alias.value()))
.collect::<Vec<_>>()
.join(", ")
);
doc.extend(quote! {
#[doc = ""]
#[doc = #aliases]
});
}
}
Ok(doc)
}
}
pub(crate) fn expand_from_impls_derived(input: DeriveInput) -> TokenStream {
let variants = match &input.data {
Data::Enum(DataEnum { variants, .. }) => variants,
_ => panic!("this derive macro only works with enums"),
};
let from_impls = variants.iter().map(|variant| match &variant.fields {
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
let inner_struct = &fields.unnamed.first().unwrap().ty;
let var_ident = &variant.ident;
let id = &input.ident;
quote! {
#[automatically_derived]
impl ::std::convert::From<#inner_struct> for #id {
fn from(c: #inner_struct) -> Self {
Self::#var_ident(c)
}
}
}
}
_ => {
panic!("this derive macro only works with enum variants with a single unnamed field")
}
});
quote! {
#( #from_impls )*
}
}
// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventEnumVariation {
None,
Sync,
Stripped,
Initial,
}
impl From<EventEnumVariation> for super::event_parse::EventKindVariation {
fn from(v: EventEnumVariation) -> Self {
match v {
EventEnumVariation::None => Self::None,
EventEnumVariation::Sync => Self::Sync,
EventEnumVariation::Stripped => Self::Stripped,
EventEnumVariation::Initial => Self::Initial,
}
}
}
// FIXME: Duplicated with the other EventKindVariation type
impl EventEnumVariation {
pub fn to_sync(self) -> Self {
match self {
EventEnumVariation::None => EventEnumVariation::Sync,
_ => panic!("No sync form of {self:?}"),
}
}
pub fn to_full(self) -> Self {
match self {
EventEnumVariation::Sync => EventEnumVariation::None,
_ => panic!("No full form of {self:?}"),
}
}
}
impl IdentFragment for EventEnumVariation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EventEnumVariation::None => write!(f, ""),
EventEnumVariation::Sync => write!(f, "Sync"),
EventEnumVariation::Stripped => write!(f, "Stripped"),
EventEnumVariation::Initial => write!(f, "Initial"),
}
}
}