events: Add accessors for state events' original or redacted content

This commit is contained in:
Kévin Commaille 2022-12-19 14:13:12 +01:00 committed by GitHub
parent 284b797e05
commit baaf73adbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 132 additions and 2 deletions

View File

@ -62,6 +62,7 @@ Improvements:
* `Ruleset::set_actions` to change the actions of push rules * `Ruleset::set_actions` to change the actions of push rules
* Add support for bundled reference relations (MSC3267 / Matrix 1.5) * Add support for bundled reference relations (MSC3267 / Matrix 1.5)
* Add the `formatted` field on `KeyVerificationRequestEventContent` (Matrix 1.5) * Add the `formatted` field on `KeyVerificationRequestEventContent` (Matrix 1.5)
* Add `content` accessors for `Any*StateEvent` enums
# 0.10.5 # 0.10.5

View File

@ -417,6 +417,28 @@ pub struct DecryptedMegolmV1Event<C: MessageLikeEventContent> {
pub room_id: OwnedRoomId, pub room_id: OwnedRoomId,
} }
/// A possibly-redacted state event content.
///
/// A non-redacted content also contains the `prev_content` from the unsigned event data.
#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Debug)]
pub enum FullStateEventContent<C: StateEventContent + RedactContent>
where
C::Redacted: RedactedStateEventContent,
{
/// Original, unredacted content of the event.
Original {
/// Current content of the room state.
content: C,
/// Previous content of the room state.
prev_content: Option<C>,
},
/// Redacted content of the event.
Redacted(C::Redacted),
}
macro_rules! impl_possibly_redacted_event { macro_rules! impl_possibly_redacted_event {
( (
$ty:ident ( $content_trait:ident, $redacted_content_trait:ident, $event_type:ident ) $ty:ident ( $content_trait:ident, $redacted_content_trait:ident, $event_type:ident )

View File

@ -87,6 +87,7 @@ pub fn expand_event_enums(input: &EventEnumDecl) -> syn::Result<TokenStream> {
} }
if matches!(kind, EventKind::State) { if matches!(kind, EventKind::State) {
res.extend(expand_full_content_enum(kind, events, docs, attrs, variants, ruma_common));
res.extend( res.extend(
expand_event_enum(kind, V::Stripped, events, docs, attrs, variants, ruma_common) expand_event_enum(kind, V::Stripped, events, docs, attrs, variants, ruma_common)
.unwrap_or_else(syn::Error::into_compile_error), .unwrap_or_else(syn::Error::into_compile_error),
@ -125,7 +126,8 @@ fn expand_event_enum(
let custom_ty = format_ident!("Custom{}Content", kind); let custom_ty = format_ident!("Custom{}Content", kind);
let deserialize_impl = expand_deserialize_impl(kind, var, events, ruma_common)?; let deserialize_impl = expand_deserialize_impl(kind, var, events, ruma_common)?;
let field_accessor_impl = expand_accessor_methods(kind, var, variants, ruma_common)?; let field_accessor_impl =
expand_accessor_methods(kind, var, variants, &event_struct, ruma_common)?;
let from_impl = expand_from_impl(&ident, &content, variants); let from_impl = expand_from_impl(&ident, &content, variants);
Ok(quote! { Ok(quote! {
@ -419,10 +421,51 @@ fn expand_content_enum(
}) })
} }
/// Create a full content enum from `EventEnumInput`.
fn expand_full_content_enum(
kind: EventKind,
events: &[EventEnumEntry],
docs: &[TokenStream],
attrs: &[Attribute],
variants: &[EventEnumVariant],
ruma_common: &TokenStream,
) -> syn::Result<TokenStream> {
let ident = kind.to_full_content_enum();
let content: Vec<_> = events
.iter()
.map(|event| {
let stable_name = event.stable_name()?;
Ok(to_event_content_path(kind, stable_name, &event.ev_path, None))
})
.collect::<syn::Result<_>>()?;
let variant_decls = variants.iter().map(|v| v.decl()).collect::<Vec<_>>();
Ok(quote! {
#( #attrs )*
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum #ident {
#(
#docs
#variant_decls(#ruma_common::events::FullStateEventContent<#content>),
)*
#[doc(hidden)]
_Custom {
event_type: crate::PrivOwnedStr,
redacted: bool,
},
}
})
}
fn expand_accessor_methods( fn expand_accessor_methods(
kind: EventKind, kind: EventKind,
var: EventEnumVariation, var: EventEnumVariation,
variants: &[EventEnumVariant], variants: &[EventEnumVariant],
event_struct: &Ident,
ruma_common: &TokenStream, ruma_common: &TokenStream,
) -> syn::Result<TokenStream> { ) -> syn::Result<TokenStream> {
let ident = kind.to_event_enum_ident(var.into())?; let ident = kind.to_event_enum_ident(var.into())?;
@ -450,7 +493,7 @@ fn expand_accessor_methods(
let content_enum = kind.to_content_enum(); let content_enum = kind.to_content_enum();
let content_variants: Vec<_> = variants.iter().map(|v| v.ctor(&content_enum)).collect(); let content_variants: Vec<_> = variants.iter().map(|v| v.ctor(&content_enum)).collect();
let content_accessor = if maybe_redacted { let content_accessor = if maybe_redacted {
quote! { let mut accessors = quote! {
/// Returns the content for this event if it is not redacted, or `None` if it is. /// Returns the content for this event if it is not redacted, or `None` if it is.
pub fn original_content(&self) -> Option<#content_enum> { pub fn original_content(&self) -> Option<#content_enum> {
match self { match self {
@ -474,7 +517,66 @@ fn expand_accessor_methods(
}), }),
} }
} }
};
if kind == EventKind::State {
let full_content_enum = kind.to_full_content_enum();
let full_content_variants: Vec<_> =
variants.iter().map(|v| v.ctor(&full_content_enum)).collect();
accessors = quote! {
#accessors
/// Returns the content of this state event.
pub fn content(&self) -> #full_content_enum {
match self {
#(
#self_variants(event) => match event {
#ruma_common::events::#event_struct::Original(ev) => #full_content_variants(
#ruma_common::events::FullStateEventContent::Original {
content: ev.content.clone(),
prev_content: ev.unsigned.prev_content.clone()
}
),
#ruma_common::events::#event_struct::Redacted(ev) => #full_content_variants(
#ruma_common::events::FullStateEventContent::Redacted(
ev.content.clone()
)
),
}
)*
Self::_Custom(event) => match event {
#ruma_common::events::#event_struct::Original(ev) => {
#full_content_enum::_Custom {
event_type: crate::PrivOwnedStr(
::std::string::ToString::to_string(
&#ruma_common::events::EventContent::event_type(
&ev.content,
),
).into_boxed_str(),
),
redacted: false,
}
}
#ruma_common::events::#event_struct::Redacted(ev) => {
#full_content_enum::_Custom {
event_type: crate::PrivOwnedStr(
::std::string::ToString::to_string(
&#ruma_common::events::EventContent::event_type(
&ev.content,
),
).into_boxed_str(),
),
redacted: true,
}
}
},
}
}
};
} }
accessors
} else { } else {
quote! { quote! {
/// Returns the content for this event. /// Returns the content for this event.

View File

@ -147,6 +147,11 @@ impl EventKind {
pub fn to_content_enum(self) -> Ident { pub fn to_content_enum(self) -> Ident {
format_ident!("Any{}Content", self) format_ident!("Any{}Content", self)
} }
/// `AnyFull[kind]EventContent`
pub fn to_full_content_enum(self) -> Ident {
format_ident!("AnyFull{}Content", self)
}
} }
impl Parse for EventKind { impl Parse for EventKind {