events: Generate From impls for event (content) enums
This commit is contained in:
parent
1eb50937d5
commit
d746244241
@ -2,7 +2,7 @@
|
||||
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use syn::{Attribute, Ident, LitStr};
|
||||
use syn::{Attribute, Data, DataEnum, DeriveInput, Ident, LitStr};
|
||||
|
||||
use crate::event_parse::{EventEnumDecl, EventEnumEntry, EventKind, EventKindVariation};
|
||||
|
||||
@ -186,6 +186,8 @@ fn expand_any_with_deser(
|
||||
|
||||
let redact_impl = expand_redact(&ident, kind, var, variants, ruma_events);
|
||||
|
||||
let from_impl = expand_from_impl(ident, &content, variants);
|
||||
|
||||
Some(quote! {
|
||||
#any_enum
|
||||
|
||||
@ -198,9 +200,34 @@ fn expand_any_with_deser(
|
||||
#event_deserialize_impl
|
||||
|
||||
#redacted_enum
|
||||
|
||||
#from_impl
|
||||
})
|
||||
}
|
||||
|
||||
fn expand_from_impl(
|
||||
ty: Ident,
|
||||
content: &[TokenStream],
|
||||
variants: &[EventEnumVariant],
|
||||
) -> TokenStream {
|
||||
let from_impls = content.iter().zip(variants).map(|(content, variant)| {
|
||||
let ident = &variant.ident;
|
||||
let attrs = &variant.attrs;
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
#(#attrs)*
|
||||
impl From<#content> for #ty {
|
||||
fn from(c: #content) -> Self {
|
||||
Self::#ident(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! { #( #from_impls )* }
|
||||
}
|
||||
|
||||
fn expand_conversion_impl(
|
||||
kind: &EventKind,
|
||||
var: &EventKindVariation,
|
||||
@ -489,11 +516,14 @@ fn expand_content_enum(
|
||||
}
|
||||
});
|
||||
|
||||
let from_impl = expand_from_impl(ident, &content, variants);
|
||||
|
||||
quote! {
|
||||
#content_enum
|
||||
#event_content_impl
|
||||
#marker_trait_impl
|
||||
#redacted_content_enum
|
||||
#from_impl
|
||||
}
|
||||
}
|
||||
|
||||
@ -1037,3 +1067,32 @@ impl EventEnumEntry {
|
||||
Ok(EventEnumVariant { attrs, ident })
|
||||
}
|
||||
}
|
||||
|
||||
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! {
|
||||
impl 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 )*
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ use proc_macro_crate::{crate_name, FoundCrate};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{parse_macro_input, DeriveInput};
|
||||
|
||||
use crate::event_enum::expand_from_impls_derived;
|
||||
|
||||
use self::{
|
||||
event::expand_event, event_content::expand_event_content, event_enum::expand_event_enum,
|
||||
event_type::expand_event_type_enum,
|
||||
@ -107,3 +109,10 @@ pub(crate) fn import_ruma_events() -> pm2::TokenStream {
|
||||
quote! { ::ruma_events }
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates `From` implementations for event enums.
|
||||
#[proc_macro_derive(EventEnumFromEvent)]
|
||||
pub fn derive_from_event_to_enum(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
expand_from_impls_derived(input).into()
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
# [unreleased]
|
||||
|
||||
Improvements:
|
||||
|
||||
* Add `From` implementations for event and event content enums
|
||||
|
||||
# 0.24.4
|
||||
|
||||
Improvements:
|
||||
|
@ -1,5 +1,5 @@
|
||||
use ruma_common::MilliSecondsSinceUnixEpoch;
|
||||
use ruma_events_macros::event_enum;
|
||||
use ruma_events_macros::{event_enum, EventEnumFromEvent};
|
||||
use ruma_identifiers::{EventId, RoomId, RoomVersionId, UserId};
|
||||
use serde::{de, Deserialize, Serialize};
|
||||
use serde_json::value::RawValue as RawJsonValue;
|
||||
@ -146,7 +146,7 @@ macro_rules! room_ev_accessor {
|
||||
|
||||
/// Any room event.
|
||||
#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
#[derive(Clone, Debug, Serialize, EventEnumFromEvent)]
|
||||
#[serde(untagged)]
|
||||
pub enum AnyRoomEvent {
|
||||
/// Any message event.
|
||||
@ -171,7 +171,7 @@ impl AnyRoomEvent {
|
||||
|
||||
/// Any sync room event (room event without a `room_id`, as returned in `/sync` responses)
|
||||
#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
#[derive(Clone, Debug, Serialize, EventEnumFromEvent)]
|
||||
#[serde(untagged)]
|
||||
pub enum AnySyncRoomEvent {
|
||||
/// Any sync message event
|
||||
@ -264,7 +264,7 @@ impl<'de> Deserialize<'de> for AnySyncRoomEvent {
|
||||
|
||||
/// Any redacted room event.
|
||||
#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, EventEnumFromEvent)]
|
||||
pub enum AnyRedactedRoomEvent {
|
||||
/// Any message event that has been redacted.
|
||||
Message(AnyRedactedMessageEvent),
|
||||
@ -300,7 +300,7 @@ impl From<AnyRedactedRoomEvent> for AnyRoomEvent {
|
||||
|
||||
/// Any redacted sync room event (room event without a `room_id`, as returned in `/sync` responses)
|
||||
#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, EventEnumFromEvent)]
|
||||
pub enum AnyRedactedSyncRoomEvent {
|
||||
/// Any sync message event that has been redacted.
|
||||
Message(AnyRedactedSyncMessageEvent),
|
||||
|
Loading…
x
Reference in New Issue
Block a user