events: Implement Redact for event structs

… it was only implemented for the enums before.
This commit is contained in:
Jonas Platte 2021-10-02 01:19:36 +02:00
parent 3b786d8f78
commit e41abbb56b
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
3 changed files with 121 additions and 52 deletions

View File

@ -1,9 +1,10 @@
//! Implementation of the top level `*Event` derive macro.
use proc_macro2::{Span, TokenStream};
use quote::quote;
use quote::{format_ident, quote};
use syn::{
Data, DataStruct, DeriveInput, Field, Fields, FieldsNamed, Ident, Meta, MetaList, NestedMeta,
parse_quote, Data, DataStruct, DeriveInput, Field, Fields, FieldsNamed, GenericParam, Ident,
Meta, MetaList, NestedMeta,
};
use crate::{
@ -40,16 +41,17 @@ pub fn expand_event(input: DeriveInput) -> syn::Result<TokenStream> {
));
};
let conversion_impl = expand_from_into(&input, &kind, &var, &fields, &ruma_events);
let serialize_impl = expand_serialize_event(&input, &var, &fields, &ruma_events);
let deserialize_impl = expand_deserialize_event(&input, &kind, &var, &fields, &ruma_events)?;
let conversion_impl = expand_from_into(&input, &kind, &var, &fields, &ruma_events);
let redact_impl = expand_redact_event(&input, &kind, &var, &fields, &ruma_events);
let eq_impl = expand_eq_ord_event(&input, &fields);
Ok(quote! {
#conversion_impl
#serialize_impl
#deserialize_impl
#redact_impl
#eq_impl
})
}
@ -391,6 +393,74 @@ fn expand_deserialize_event(
})
}
fn expand_redact_event(
input: &DeriveInput,
kind: &EventKind,
var: &EventKindVariation,
fields: &[Field],
ruma_events: &TokenStream,
) -> Option<TokenStream> {
let ruma_identifiers = quote! { #ruma_events::exports::ruma_identifiers };
let redacted_type = kind.to_event_ident(&var.to_redacted()?)?;
let redacted_content_trait =
format_ident!("{}Content", kind.to_event_ident(&EventKindVariation::Redacted).unwrap());
let ident = &input.ident;
let mut generics = input.generics.clone();
assert_eq!(generics.params.len(), 1, "expected one generic parameter");
let ty_param = match &generics.params[0] {
GenericParam::Type(ty) => ty.ident.clone(),
_ => panic!("expected a type parameter"),
};
let where_clause = generics.make_where_clause();
where_clause.predicates.push(parse_quote! { #ty_param: #ruma_events::RedactContent });
where_clause.predicates.push(parse_quote! {
<#ty_param as #ruma_events::RedactContent>::Redacted:
#ruma_events::#redacted_content_trait
});
let (impl_generics, ty_gen, where_clause) = generics.split_for_impl();
let fields = fields.iter().filter_map(|field| {
let ident = field.ident.as_ref().unwrap();
if ident == "content" || ident == "prev_content" {
None
} else if ident == "unsigned" {
Some(quote! {
unsigned:
#ruma_events::RedactedUnsigned::new_because(::std::boxed::Box::new(redaction))
})
} else {
Some(quote! {
#ident: self.#ident
})
}
});
Some(quote! {
#[automatically_derived]
impl #impl_generics #ruma_events::Redact for #ident #ty_gen #where_clause {
type Redacted =
#ruma_events::#redacted_type<<#ty_param as #ruma_events::RedactContent>::Redacted>;
fn redact(
self,
redaction: #ruma_events::room::redaction::SyncRedactionEvent,
version: &#ruma_identifiers::RoomVersionId,
) -> Self::Redacted {
let content = #ruma_events::RedactContent::redact(self.content, version);
#ruma_events::#redacted_type {
content,
#(#fields),*
}
}
}
})
}
fn expand_from_into(
input: &DeriveInput,
kind: &EventKind,

View File

@ -464,20 +464,10 @@ fn expand_redact(
) -> Option<TokenStream> {
let ruma_identifiers = quote! { #ruma_events::exports::ruma_identifiers };
let redacted_var = var.to_redacted()?;
let struct_id = kind.to_event_ident(&redacted_var)?;
let redacted_enum = kind.to_event_enum_ident(&redacted_var)?;
let redacted_type = quote! { #ruma_events::#struct_id };
let redacted_enum = kind.to_event_enum_ident(&var.to_redacted()?)?;
let self_variants = variants.iter().map(|v| v.match_arm(quote! { Self }));
let redaction_variants = variants.iter().map(|v| v.ctor(&redacted_enum));
let fields = EVENT_FIELDS.iter().map(|(name, has_field)| {
generate_redacted_fields(name, kind, var, *has_field, ruma_events)
});
let fields = quote! { #( #fields )* };
Some(quote! {
#[automatically_derived]
impl #ruma_events::Redact for #ident {
@ -490,21 +480,13 @@ fn expand_redact(
) -> #redacted_enum {
match self {
#(
#self_variants(event) => {
let content = #ruma_events::RedactContent::redact(event.content, version);
#redaction_variants(#redacted_type {
content,
#fields
})
}
#self_variants(event) => #redaction_variants(
#ruma_events::Redact::redact(event, redaction, version),
),
)*
Self::_Custom(event) => {
let content = #ruma_events::RedactContent::redact(event.content, version);
#redacted_enum::_Custom(#redacted_type {
content,
#fields
})
}
Self::_Custom(event) => #redacted_enum::_Custom(
#ruma_events::Redact::redact(event, redaction, version),
)
}
}
}
@ -564,28 +546,6 @@ fn generate_event_idents(kind: &EventKind, var: &EventKindVariation) -> Option<(
kind.to_event_ident(var).zip(kind.to_event_enum_ident(var))
}
fn generate_redacted_fields(
name: &str,
kind: &EventKind,
var: &EventKindVariation,
is_event_kind: EventKindFn,
ruma_events: &TokenStream,
) -> Option<TokenStream> {
is_event_kind(kind, var).then(|| {
let name = Ident::new(name, Span::call_site());
if name == "unsigned" {
quote! {
unsigned: #ruma_events::RedactedUnsigned::new_because(::std::boxed::Box::new(redaction)),
}
} else {
quote! {
#name: event.#name,
}
}
})
}
fn generate_custom_variant(
event_struct: &Ident,
var: &EventKindVariation,

View File

@ -5,7 +5,7 @@ use ruma_events_macros::{Event, EventContent};
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{Deserialize, Serialize};
use crate::Unsigned;
use crate::{Redact, RedactContent, RedactedUnsigned, Unsigned};
/// Redaction event.
#[derive(Clone, Debug, Event)]
@ -33,6 +33,26 @@ pub struct RedactionEvent {
pub unsigned: Unsigned,
}
impl Redact for RedactionEvent {
// Temporary hack
type Redacted = crate::RedactedMessageEvent<RedactedRedactionEventContent>;
fn redact(
self,
redaction: SyncRedactionEvent,
version: &ruma_identifiers::RoomVersionId,
) -> Self::Redacted {
crate::RedactedMessageEvent {
content: self.content.redact(version),
event_id: self.event_id,
sender: self.sender,
origin_server_ts: self.origin_server_ts,
room_id: self.room_id,
unsigned: RedactedUnsigned::new_because(Box::new(redaction)),
}
}
}
/// Redaction event without a `room_id`.
#[derive(Clone, Debug, Event)]
#[allow(clippy::exhaustive_structs)]
@ -56,6 +76,25 @@ pub struct SyncRedactionEvent {
pub unsigned: Unsigned,
}
impl Redact for SyncRedactionEvent {
// Temporary hack
type Redacted = crate::RedactedSyncMessageEvent<RedactedRedactionEventContent>;
fn redact(
self,
redaction: SyncRedactionEvent,
version: &ruma_identifiers::RoomVersionId,
) -> Self::Redacted {
crate::RedactedSyncMessageEvent {
content: self.content.redact(version),
event_id: self.event_id,
sender: self.sender,
origin_server_ts: self.origin_server_ts,
unsigned: RedactedUnsigned::new_because(Box::new(redaction)),
}
}
}
/// A redaction of an event.
#[derive(Clone, Debug, Default, Deserialize, Serialize, EventContent)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]