Generate EventKind/Variation pair from Event derive input

This commit is contained in:
Devin R 2020-07-22 15:20:22 -04:00 committed by Jonas Platte
parent 4b9fdcb189
commit a39c0106d4
2 changed files with 63 additions and 5 deletions

View File

@ -4,9 +4,15 @@ use proc_macro2::{Span, TokenStream};
use quote::quote; use quote::quote;
use syn::{Data, DataStruct, DeriveInput, Field, Fields, FieldsNamed, Ident}; use syn::{Data, DataStruct, DeriveInput, Field, Fields, FieldsNamed, Ident};
use crate::event_parse::{to_kind_variation, EventKindVariation};
/// Derive `Event` macro code generation. /// Derive `Event` macro code generation.
pub fn expand_event(input: DeriveInput) -> syn::Result<TokenStream> { pub fn expand_event(input: DeriveInput) -> syn::Result<TokenStream> {
let ident = &input.ident; let ident = &input.ident;
let (_kind, var) = to_kind_variation(ident)
.ok_or(syn::Error::new(Span::call_site(), "not a valid ruma event struct identifier"))?;
let (impl_gen, ty_gen, where_clause) = input.generics.split_for_impl(); let (impl_gen, ty_gen, where_clause) = input.generics.split_for_impl();
let is_generic = !input.generics.params.is_empty(); let is_generic = !input.generics.params.is_empty();
@ -37,7 +43,12 @@ pub fn expand_event(input: DeriveInput) -> syn::Result<TokenStream> {
.iter() .iter()
.map(|field| { .map(|field| {
let name = field.ident.as_ref().unwrap(); let name = field.ident.as_ref().unwrap();
if name == "content" && ident.to_string().contains("Redacted") { if name == "content" && matches!(
var,
EventKindVariation::Redacted
| EventKindVariation::RedactedSync
| EventKindVariation::RedactedStripped
) {
quote! { quote! {
if ::ruma_events::RedactedEventContent::has_serialize_fields(&self.content) { if ::ruma_events::RedactedEventContent::has_serialize_fields(&self.content) {
state.serialize_field("content", &self.content)?; state.serialize_field("content", &self.content)?;
@ -92,7 +103,7 @@ pub fn expand_event(input: DeriveInput) -> syn::Result<TokenStream> {
} }
}; };
let deserialize_impl = expand_deserialize_event(is_generic, input, fields)?; let deserialize_impl = expand_deserialize_event(input, &var, fields, is_generic)?;
Ok(quote! { Ok(quote! {
#serialize_impl #serialize_impl
@ -102,9 +113,10 @@ pub fn expand_event(input: DeriveInput) -> syn::Result<TokenStream> {
} }
fn expand_deserialize_event( fn expand_deserialize_event(
is_generic: bool,
input: DeriveInput, input: DeriveInput,
var: &EventKindVariation,
fields: Vec<Field>, fields: Vec<Field>,
is_generic: bool,
) -> syn::Result<TokenStream> { ) -> syn::Result<TokenStream> {
let ident = &input.ident; let ident = &input.ident;
// we know there is a content field already // we know there is a content field already
@ -149,7 +161,12 @@ fn expand_deserialize_event(
.map(|field| { .map(|field| {
let name = field.ident.as_ref().unwrap(); let name = field.ident.as_ref().unwrap();
if name == "content" { if name == "content" {
if is_generic && ident.to_string().contains("Redacted") { if is_generic && matches!(
var,
EventKindVariation::Redacted
| EventKindVariation::RedactedSync
| EventKindVariation::RedactedStripped
) {
quote! { quote! {
let content = match C::has_deserialize_fields() { let content = match C::has_deserialize_fields() {
::ruma_events::HasDeserializeFields::False => { ::ruma_events::HasDeserializeFields::False => {

View File

@ -22,6 +22,7 @@ pub enum EventKindVariation {
Redacted, Redacted,
RedactedSync, RedactedSync,
RedactedStripped, RedactedStripped,
ManuallyImpled,
} }
// If the variants of this enum change `to_event_path` needs to be updated as well. // If the variants of this enum change `to_event_path` needs to be updated as well.
@ -31,6 +32,7 @@ pub enum EventKind {
Message(Ident), Message(Ident),
State(Ident), State(Ident),
ToDevice(Ident), ToDevice(Ident),
ManuallyImpled(Ident),
} }
impl EventKind { impl EventKind {
@ -78,7 +80,8 @@ impl EventKind {
| EventKind::Ephemeral(i) | EventKind::Ephemeral(i)
| EventKind::Message(i) | EventKind::Message(i)
| EventKind::State(i) | EventKind::State(i)
| EventKind::ToDevice(i) => i, | EventKind::ToDevice(i)
| EventKind::ManuallyImpled(i) => i,
} }
} }
} }
@ -105,6 +108,44 @@ impl Parse for EventKind {
} }
} }
pub fn to_kind_variation(ident: &Ident) -> Option<(EventKind, EventKindVariation)> {
let ident_str = ident.to_string();
match ident_str.as_str() {
"BasicEvent" => Some((EventKind::Basic(ident.clone()), EventKindVariation::Full)),
"EphemeralRoomEvent" => Some((EventKind::Basic(ident.clone()), EventKindVariation::Full)),
"SyncEphemeralRoomEvent" => {
Some((EventKind::Basic(ident.clone()), EventKindVariation::Sync))
}
"MessageEvent" => Some((EventKind::Basic(ident.clone()), EventKindVariation::Full)),
"SyncMessageEvent" => Some((EventKind::Basic(ident.clone()), EventKindVariation::Sync)),
"RedactedMessageEvent" => {
Some((EventKind::Basic(ident.clone()), EventKindVariation::Redacted))
}
"RedactedSyncMessageEvent" => {
Some((EventKind::Basic(ident.clone()), EventKindVariation::RedactedSync))
}
"StateEvent" => Some((EventKind::Basic(ident.clone()), EventKindVariation::Full)),
"SyncStateEvent" => Some((EventKind::Basic(ident.clone()), EventKindVariation::Sync)),
"StrippedStateEvent" => {
Some((EventKind::Basic(ident.clone()), EventKindVariation::Stripped))
}
"RedactedStateEvent" => {
Some((EventKind::Basic(ident.clone()), EventKindVariation::Redacted))
}
"RedactedSyncStateEvent" => {
Some((EventKind::Basic(ident.clone()), EventKindVariation::RedactedSync))
}
"RedactedStrippedStateEvent" => {
Some((EventKind::Basic(ident.clone()), EventKindVariation::RedactedStripped))
}
"ToDeviceEvent" => Some((EventKind::Basic(ident.clone()), EventKindVariation::Full)),
"PresenceEvent" | "RedactionEvent" | "SyncRedactionEvent" => {
Some((EventKind::ManuallyImpled(ident.clone()), EventKindVariation::ManuallyImpled))
}
_ => None,
}
}
/// The entire `event_enum!` macro structure directly as it appears in the source code. /// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumInput { pub struct EventEnumInput {
/// Outer attributes on the field, such as a docstring. /// Outer attributes on the field, such as a docstring.