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