From c7c1251f3fca2dfb64906e75edb922e07a45b460 Mon Sep 17 00:00:00 2001 From: Devin Ragotzy Date: Thu, 13 May 2021 15:35:26 -0400 Subject: [PATCH] Specify content traits in attribute, remove derives --- .../ruma-events-macros/src/event_content.rs | 179 +++++++++--------- crates/ruma-events-macros/src/lib.rs | 55 +----- crates/ruma-events/src/lib.rs | 10 +- 3 files changed, 94 insertions(+), 150 deletions(-) diff --git a/crates/ruma-events-macros/src/event_content.rs b/crates/ruma-events-macros/src/event_content.rs index b3dc1a86..c9235f9c 100644 --- a/crates/ruma-events-macros/src/event_content.rs +++ b/crates/ruma-events-macros/src/event_content.rs @@ -7,11 +7,15 @@ use syn::{ DeriveInput, Ident, LitStr, Token, }; +use crate::event_parse::EventKind; + mod kw { // This `content` field is kept when the event is redacted. syn::custom_keyword!(skip_redaction); // Do not emit any redacted event code. syn::custom_keyword!(custom_redacted); + // The kind of event content this is. + syn::custom_keyword!(kind); } /// Parses attributes for `*EventContent` derives. @@ -21,6 +25,8 @@ enum EventMeta { /// Variant holds the "m.whatever" event type. Type(LitStr), + Kind(EventKind), + /// Fields marked with `#[ruma_event(skip_redaction)]` are kept when the event is /// redacted. SkipRedacted, @@ -38,6 +44,14 @@ impl EventMeta { None } } + + fn get_event_kind(&self) -> Option<&EventKind> { + if let Self::Kind(lit) = self { + Some(lit) + } else { + None + } + } } impl Parse for EventMeta { @@ -47,6 +61,10 @@ impl Parse for EventMeta { let _: Token![type] = input.parse()?; let _: Token![=] = input.parse()?; input.parse().map(EventMeta::Type) + } else if lookahead.peek(kw::kind) { + let _: kw::kind = input.parse()?; + let _: Token![=] = input.parse()?; + EventKind::parse(input).map(EventMeta::Kind) } else if lookahead.peek(kw::skip_redaction) { let _: kw::skip_redaction = input.parse()?; Ok(EventMeta::SkipRedacted) @@ -69,6 +87,10 @@ impl MetaAttrs { fn get_event_type(&self) -> Option<&LitStr> { self.0.iter().find_map(|a| a.get_event_type()) } + + fn get_event_kinds(&self) -> Vec<&EventKind> { + self.0.iter().filter_map(|a| a.get_event_kind()).collect() + } } impl Parse for MetaAttrs { @@ -81,7 +103,6 @@ impl Parse for MetaAttrs { /// Create an `EventContent` implementation for a struct. pub fn expand_event_content( input: &DeriveInput, - emit_redacted: bool, ruma_events: &TokenStream, ) -> syn::Result { let ruma_identifiers = quote! { #ruma_events::exports::ruma_identifiers }; @@ -99,13 +120,16 @@ pub fn expand_event_content( let event_type = content_attr.iter().find_map(|a| a.get_event_type()).ok_or_else(|| { let msg = "no event type attribute found, \ - add `#[ruma_event(type = \"any.room.event\")]` \ + add `#[ruma_event(type = \"any.room.event\", kind = Kind)]` \ below the event content derive"; syn::Error::new(Span::call_site(), msg) })?; - let redacted = if emit_redacted && needs_redacted(&content_attr) { + let content_derives = + content_attr.iter().flat_map(|args| args.get_event_kinds()).collect::>(); + + let redacted = if needs_redacted(&content_attr) { let doc = format!("The payload for a redacted `{}`", ident); let redacted_ident = format_ident!("Redacted{}", ident); let kept_redacted_fields = if let syn::Data::Struct(syn::DataStruct { @@ -182,6 +206,21 @@ pub fn expand_event_content( let redacted_event_content = generate_event_content_impl(&redacted_ident, event_type, ruma_events); + let redacted_event_content_derive = content_derives + .iter() + .map(|kind| match kind { + EventKind::Message => quote! { + #[automatically_derived] + impl #ruma_events::RedactedMessageEventContent for #redacted_ident {} + }, + EventKind::State => quote! { + #[automatically_derived] + impl #ruma_events::RedactedStateEventContent for #redacted_ident {} + }, + _ => TokenStream::new(), + }) + .collect::(); + quote! { // this is the non redacted event content's impl #[automatically_derived] @@ -220,106 +259,68 @@ pub fn expand_event_content( #has_deserialize_fields } } + + #redacted_event_content_derive } } else { TokenStream::new() }; + let event_content_derive = + generate_event_content_derives(&content_derives, ident, ruma_events)?; + let event_content = generate_event_content_impl(ident, event_type, ruma_events); Ok(quote! { #event_content + #event_content_derive + #redacted }) } -/// Create a `EphemeralRoomEventContent` implementation for a struct -pub fn expand_ephemeral_room_event_content( - input: &DeriveInput, +fn generate_event_content_derives( + content_attr: &[&EventKind], + ident: &Ident, ruma_events: &TokenStream, ) -> syn::Result { - let ident = input.ident.clone(); - let event_content_impl = expand_event_content(input, false, ruma_events)?; - - Ok(quote! { - #event_content_impl - - #[automatically_derived] - impl #ruma_events::EphemeralRoomEventContent for #ident {} - }) -} - -/// Create a `RoomEventContent` implementation for a struct. -pub fn expand_room_event_content( - input: &DeriveInput, - ruma_events: &TokenStream, -) -> syn::Result { - let ident = input.ident.clone(); - let event_content_impl = expand_event_content(input, true, ruma_events)?; - - Ok(quote! { - #event_content_impl - - #[automatically_derived] - impl #ruma_events::RoomEventContent for #ident {} - }) -} - -/// Create a `MessageEventContent` implementation for a struct -pub fn expand_message_event_content( - input: &DeriveInput, - ruma_events: &TokenStream, -) -> syn::Result { - let ident = input.ident.clone(); - let room_ev_content = expand_room_event_content(input, ruma_events)?; - - let redacted_marker_trait = if needs_redacted_from_input(input) { - let ident = format_ident!("Redacted{}", &ident); - quote! { - #[automatically_derived] - impl #ruma_events::RedactedMessageEventContent for #ident {} - } - } else { - TokenStream::new() - }; - - Ok(quote! { - #room_ev_content - - #[automatically_derived] - impl #ruma_events::MessageEventContent for #ident {} - - #redacted_marker_trait - }) -} - -/// Create a `StateEventContent` implementation for a struct -pub fn expand_state_event_content( - input: &DeriveInput, - ruma_events: &TokenStream, -) -> syn::Result { - let ident = input.ident.clone(); - let room_ev_content = expand_room_event_content(input, ruma_events)?; - - let redacted_marker_trait = if needs_redacted_from_input(input) { - let ident = format_ident!("Redacted{}", input.ident); - quote! { - #[automatically_derived] - impl #ruma_events::RedactedStateEventContent for #ident {} - } - } else { - TokenStream::new() - }; - - Ok(quote! { - #room_ev_content - - #[automatically_derived] - impl #ruma_events::StateEventContent for #ident {} - - #redacted_marker_trait - }) + let msg = "valid event kinds are GlobalAccountData, RoomAccountData, \ + EphemeralRoom, Message, State, ToDevice"; + content_attr + .iter() + .map(|kind| { + Ok(match kind { + EventKind::GlobalAccountData => quote! { + // TODO: will this be it's own trait at some point? + }, + EventKind::RoomAccountData => quote! { + // TODO: will this be it's own trait at some point? + }, + EventKind::Ephemeral => quote! { + #[automatically_derived] + impl #ruma_events::EphemeralRoomEventContent for #ident {} + }, + EventKind::Message => quote! { + #[automatically_derived] + impl #ruma_events::RoomEventContent for #ident {} + #[automatically_derived] + impl #ruma_events::MessageEventContent for #ident {} + }, + EventKind::State => quote! { + #[automatically_derived] + impl #ruma_events::RoomEventContent for #ident {} + #[automatically_derived] + impl #ruma_events::StateEventContent for #ident {} + }, + EventKind::ToDevice => quote! { + // TODO: will this be it's own trait at some point? + }, + EventKind::Redaction => return Err(syn::Error::new(ident.span(), msg)), + EventKind::Presence => return Err(syn::Error::new(ident.span(), msg)), + }) + }) + .collect() } fn generate_event_content_impl( @@ -359,7 +360,3 @@ fn needs_redacted(input: &[MetaAttrs]) -> bool { // needs a redacted struct generated. !input.iter().any(|a| a.is_custom()) } - -fn needs_redacted_from_input(input: &DeriveInput) -> bool { - !input.attrs.iter().flat_map(|a| a.parse_args::().ok()).any(|a| a.is_custom()) -} diff --git a/crates/ruma-events-macros/src/lib.rs b/crates/ruma-events-macros/src/lib.rs index 88757954..678c0656 100644 --- a/crates/ruma-events-macros/src/lib.rs +++ b/crates/ruma-events-macros/src/lib.rs @@ -15,12 +15,7 @@ use quote::quote; use syn::{parse_macro_input, DeriveInput, Ident}; use self::{ - event::expand_event, - event_content::{ - expand_ephemeral_room_event_content, expand_event_content, expand_message_event_content, - expand_room_event_content, expand_state_event_content, - }, - event_enum::expand_event_enum, + event::expand_event, event_content::expand_event_content, event_enum::expand_event_enum, event_parse::EventEnumInput, }; @@ -58,53 +53,7 @@ pub fn derive_event_content(input: TokenStream) -> TokenStream { let ruma_events = import_ruma_events(); let input = parse_macro_input!(input as DeriveInput); - expand_event_content(&input, true, &ruma_events) - .unwrap_or_else(syn::Error::into_compile_error) - .into() -} - -/// Generates an implementation of `ruma_events::RoomEventContent` and it's super traits. -#[proc_macro_derive(RoomEventContent, attributes(ruma_event))] -pub fn derive_room_event_content(input: TokenStream) -> TokenStream { - let ruma_events = import_ruma_events(); - let input = parse_macro_input!(input as DeriveInput); - - expand_room_event_content(&input, &ruma_events) - .unwrap_or_else(syn::Error::into_compile_error) - .into() -} - -/// Generates an implementation of `ruma_events::MessageEventContent` and it's super traits. -#[proc_macro_derive(MessageEventContent, attributes(ruma_event))] -pub fn derive_message_event_content(input: TokenStream) -> TokenStream { - let ruma_events = import_ruma_events(); - let input = parse_macro_input!(input as DeriveInput); - - expand_message_event_content(&input, &ruma_events) - .unwrap_or_else(syn::Error::into_compile_error) - .into() -} - -/// Generates an implementation of `ruma_events::StateEventContent` and it's super traits. -#[proc_macro_derive(StateEventContent, attributes(ruma_event))] -pub fn derive_state_event_content(input: TokenStream) -> TokenStream { - let ruma_events = import_ruma_events(); - let input = parse_macro_input!(input as DeriveInput); - - expand_state_event_content(&input, &ruma_events) - .unwrap_or_else(syn::Error::into_compile_error) - .into() -} - -/// Generates an implementation of `ruma_events::EphemeralRoomEventContent` and it's super traits. -#[proc_macro_derive(EphemeralRoomEventContent, attributes(ruma_event))] -pub fn derive_ephemeral_room_event_content(input: TokenStream) -> TokenStream { - let ruma_events = import_ruma_events(); - let input = parse_macro_input!(input as DeriveInput); - - expand_ephemeral_room_event_content(&input, &ruma_events) - .unwrap_or_else(syn::Error::into_compile_error) - .into() + expand_event_content(&input, &ruma_events).unwrap_or_else(syn::Error::into_compile_error).into() } /// Generates implementations needed to serialize and deserialize Matrix events. diff --git a/crates/ruma-events/src/lib.rs b/crates/ruma-events/src/lib.rs index 93224cac..26ac832e 100644 --- a/crates/ruma-events/src/lib.rs +++ b/crates/ruma-events/src/lib.rs @@ -36,7 +36,7 @@ //! would work. //! //! ```rust -//! use ruma_events::{macros::MessageEventContent, SyncMessageEvent}; +//! use ruma_events::{macros::EventContent, SyncMessageEvent}; //! use ruma_identifiers::EventId; //! use serde::{Deserialize, Serialize}; //! @@ -58,8 +58,8 @@ //! } //! //! /// The payload for our reaction event. -//! #[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)] -//! #[ruma_event(type = "m.reaction")] +//! #[derive(Clone, Debug, Deserialize, Serialize, EventContent)] +//! #[ruma_event(type = "m.reaction", kind = Message)] //! pub struct ReactionEventContent { //! #[serde(rename = "m.relates_to")] //! pub relates_to: RelatesTo, @@ -151,9 +151,7 @@ pub mod exports { /// Re-export of all the derives needed to create your own event types. pub mod macros { - pub use ruma_events_macros::{ - EphemeralRoomEventContent, Event, MessageEventContent, StateEventContent, - }; + pub use ruma_events_macros::{Event, EventContent}; } pub mod call;