events-macros: Reorganize event impl generation
This commit is contained in:
parent
7a4af83207
commit
9103ad74bb
@ -10,6 +10,7 @@ use syn::{
|
||||
use crate::{
|
||||
event_parse::{to_kind_variation, EventKind, EventKindVariation},
|
||||
import_ruma_events,
|
||||
util::is_non_stripped_room_event,
|
||||
};
|
||||
|
||||
/// Derive `Event` macro code generation.
|
||||
@ -41,19 +42,26 @@ 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 redact_impl = expand_redact_event(&input, kind, var, &fields, &ruma_events);
|
||||
let eq_impl = expand_eq_ord_event(&input, &fields);
|
||||
let mut res = TokenStream::new();
|
||||
|
||||
Ok(quote! {
|
||||
#conversion_impl
|
||||
#serialize_impl
|
||||
#deserialize_impl
|
||||
#redact_impl
|
||||
#eq_impl
|
||||
})
|
||||
res.extend(expand_serialize_event(&input, var, &fields, &ruma_events));
|
||||
res.extend(expand_deserialize_event(&input, kind, var, &fields, &ruma_events)?);
|
||||
|
||||
if var.is_sync() {
|
||||
res.extend(expand_sync_from_into_full(&input, kind, var, &fields, &ruma_events));
|
||||
}
|
||||
|
||||
if matches!(kind, EventKind::Message | EventKind::State)
|
||||
&& matches!(var, EventKindVariation::Full | EventKindVariation::Sync)
|
||||
{
|
||||
res.extend(expand_redact_event(&input, kind, var, &fields, &ruma_events));
|
||||
}
|
||||
|
||||
if is_non_stripped_room_event(kind, var) {
|
||||
res.extend(expand_eq_ord_event(&input));
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn expand_serialize_event(
|
||||
@ -405,17 +413,17 @@ fn expand_redact_event(
|
||||
var: EventKindVariation,
|
||||
fields: &[Field],
|
||||
ruma_events: &TokenStream,
|
||||
) -> Option<TokenStream> {
|
||||
) -> TokenStream {
|
||||
let ruma_identifiers = quote! { #ruma_events::exports::ruma_identifiers };
|
||||
|
||||
let redacted_type = kind.to_event_ident(var.to_redacted()?)?;
|
||||
let redacted_type = kind.to_event_ident(var.to_redacted().unwrap()).unwrap();
|
||||
let redacted_content_trait =
|
||||
format_ident!("{}Content", kind.to_event_ident(EventKindVariation::Redacted).unwrap());
|
||||
let ident = &input.ident;
|
||||
|
||||
let mut generics = input.generics.clone();
|
||||
if generics.params.is_empty() {
|
||||
return None;
|
||||
return TokenStream::new();
|
||||
}
|
||||
|
||||
assert_eq!(generics.params.len(), 1, "expected one generic parameter");
|
||||
@ -450,7 +458,7 @@ fn expand_redact_event(
|
||||
}
|
||||
});
|
||||
|
||||
Some(quote! {
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics #ruma_events::Redact for #ident #ty_gen #where_clause {
|
||||
type Redacted =
|
||||
@ -468,91 +476,83 @@ fn expand_redact_event(
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_from_into(
|
||||
fn expand_sync_from_into_full(
|
||||
input: &DeriveInput,
|
||||
kind: EventKind,
|
||||
var: EventKindVariation,
|
||||
fields: &[Field],
|
||||
ruma_events: &TokenStream,
|
||||
) -> Option<TokenStream> {
|
||||
) -> TokenStream {
|
||||
let ruma_identifiers = quote! { #ruma_events::exports::ruma_identifiers };
|
||||
|
||||
let ident = &input.ident;
|
||||
|
||||
let full_struct = kind.to_event_ident(var.to_full().unwrap()).unwrap();
|
||||
let (impl_generics, ty_gen, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
let fields: Vec<_> = fields.iter().flat_map(|f| &f.ident).collect();
|
||||
|
||||
if let EventKindVariation::Sync | EventKindVariation::RedactedSync = var {
|
||||
let full_struct = kind.to_event_ident(var.to_full().unwrap()).unwrap();
|
||||
Some(quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::std::convert::From<#full_struct #ty_gen>
|
||||
for #ident #ty_gen #where_clause
|
||||
{
|
||||
fn from(event: #full_struct #ty_gen) -> Self {
|
||||
let #full_struct { #( #fields, )* .. } = event;
|
||||
Self { #( #fields, )* }
|
||||
}
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_generics ::std::convert::From<#full_struct #ty_gen>
|
||||
for #ident #ty_gen #where_clause
|
||||
{
|
||||
fn from(event: #full_struct #ty_gen) -> Self {
|
||||
let #full_struct { #( #fields, )* .. } = event;
|
||||
Self { #( #fields, )* }
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_generics #ident #ty_gen #where_clause {
|
||||
/// Convert this sync event into a full event, one with a room_id field.
|
||||
pub fn into_full_event(
|
||||
self,
|
||||
room_id: #ruma_identifiers::RoomId,
|
||||
) -> #full_struct #ty_gen {
|
||||
let Self { #( #fields, )* } = self;
|
||||
#full_struct {
|
||||
#( #fields, )*
|
||||
room_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_eq_ord_event(input: &DeriveInput, fields: &[Field]) -> Option<TokenStream> {
|
||||
fields.iter().flat_map(|f| f.ident.as_ref()).any(|f| f == "event_id").then(|| {
|
||||
let ident = &input.ident;
|
||||
let (impl_gen, ty_gen, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_gen ::std::cmp::PartialEq for #ident #ty_gen #where_clause {
|
||||
/// Checks if two `EventId`s are equal.
|
||||
fn eq(&self, other: &Self) -> ::std::primitive::bool {
|
||||
self.event_id == other.event_id
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_gen ::std::cmp::Eq for #ident #ty_gen #where_clause {}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_gen ::std::cmp::PartialOrd for #ident #ty_gen #where_clause {
|
||||
/// Compares `EventId`s and orders them lexicographically.
|
||||
fn partial_cmp(&self, other: &Self) -> ::std::option::Option<::std::cmp::Ordering> {
|
||||
self.event_id.partial_cmp(&other.event_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_gen ::std::cmp::Ord for #ident #ty_gen #where_clause {
|
||||
/// Compares `EventId`s and orders them lexicographically.
|
||||
fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
|
||||
self.event_id.cmp(&other.event_id)
|
||||
#[automatically_derived]
|
||||
impl #impl_generics #ident #ty_gen #where_clause {
|
||||
/// Convert this sync event into a full event, one with a room_id field.
|
||||
pub fn into_full_event(
|
||||
self,
|
||||
room_id: #ruma_identifiers::RoomId,
|
||||
) -> #full_struct #ty_gen {
|
||||
let Self { #( #fields, )* } = self;
|
||||
#full_struct {
|
||||
#( #fields, )*
|
||||
room_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn expand_eq_ord_event(input: &DeriveInput) -> TokenStream {
|
||||
let ident = &input.ident;
|
||||
let (impl_gen, ty_gen, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl #impl_gen ::std::cmp::PartialEq for #ident #ty_gen #where_clause {
|
||||
/// Checks if two `EventId`s are equal.
|
||||
fn eq(&self, other: &Self) -> ::std::primitive::bool {
|
||||
self.event_id == other.event_id
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_gen ::std::cmp::Eq for #ident #ty_gen #where_clause {}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_gen ::std::cmp::PartialOrd for #ident #ty_gen #where_clause {
|
||||
/// Compares `EventId`s and orders them lexicographically.
|
||||
fn partial_cmp(&self, other: &Self) -> ::std::option::Option<::std::cmp::Ordering> {
|
||||
self.event_id.partial_cmp(&other.event_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[automatically_derived]
|
||||
impl #impl_gen ::std::cmp::Ord for #ident #ty_gen #where_clause {
|
||||
/// Compares `EventId`s and orders them lexicographically.
|
||||
fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
|
||||
self.event_id.cmp(&other.event_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// CamelCase's a field ident like "foo_bar" to "FooBar".
|
||||
|
@ -4,43 +4,10 @@ use proc_macro2::{Span, TokenStream};
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use syn::{Attribute, Data, DataEnum, DeriveInput, Ident, LitStr};
|
||||
|
||||
use crate::event_parse::{EventEnumDecl, EventEnumEntry, EventKind, EventKindVariation};
|
||||
|
||||
fn is_non_stripped_room_event(kind: EventKind, var: EventKindVariation) -> bool {
|
||||
matches!(kind, EventKind::Message | EventKind::State)
|
||||
&& matches!(
|
||||
var,
|
||||
EventKindVariation::Full
|
||||
| EventKindVariation::Sync
|
||||
| EventKindVariation::Redacted
|
||||
| EventKindVariation::RedactedSync
|
||||
)
|
||||
}
|
||||
|
||||
fn has_prev_content_field(kind: EventKind, var: EventKindVariation) -> bool {
|
||||
matches!(kind, EventKind::State)
|
||||
&& matches!(var, EventKindVariation::Full | EventKindVariation::Sync)
|
||||
}
|
||||
|
||||
type EventKindFn = fn(EventKind, EventKindVariation) -> bool;
|
||||
|
||||
/// This const is used to generate the accessor methods for the `Any*Event` enums.
|
||||
///
|
||||
/// DO NOT alter the field names unless the structs in `ruma_events::event_kinds` have changed.
|
||||
const EVENT_FIELDS: &[(&str, EventKindFn)] = &[
|
||||
("origin_server_ts", is_non_stripped_room_event),
|
||||
("room_id", |kind, var| {
|
||||
matches!(kind, EventKind::Message | EventKind::State | EventKind::Ephemeral)
|
||||
&& matches!(var, EventKindVariation::Full | EventKindVariation::Redacted)
|
||||
}),
|
||||
("event_id", is_non_stripped_room_event),
|
||||
("sender", |kind, var| {
|
||||
matches!(kind, EventKind::Message | EventKind::State | EventKind::ToDevice)
|
||||
&& var != EventKindVariation::Initial
|
||||
}),
|
||||
("state_key", |kind, _| matches!(kind, EventKind::State)),
|
||||
("unsigned", is_non_stripped_room_event),
|
||||
];
|
||||
use crate::{
|
||||
event_parse::{EventEnumDecl, EventEnumEntry, EventKind, EventKindVariation},
|
||||
util::{has_prev_content_field, EVENT_FIELDS},
|
||||
};
|
||||
|
||||
/// Create a content enum from `EventEnumInput`.
|
||||
pub fn expand_event_enums(input: &EventEnumDecl) -> syn::Result<TokenStream> {
|
||||
|
@ -45,6 +45,10 @@ impl EventKindVariation {
|
||||
matches!(self, Self::Redacted | Self::RedactedSync)
|
||||
}
|
||||
|
||||
pub fn is_sync(self) -> bool {
|
||||
matches!(self, Self::Sync | Self::RedactedSync)
|
||||
}
|
||||
|
||||
pub fn to_redacted(self) -> Option<Self> {
|
||||
match self {
|
||||
EventKindVariation::Full => Some(EventKindVariation::Redacted),
|
||||
|
@ -27,6 +27,7 @@ mod event_content;
|
||||
mod event_enum;
|
||||
mod event_parse;
|
||||
mod event_type;
|
||||
mod util;
|
||||
|
||||
/// Generates an enum to represent the various Matrix event types.
|
||||
///
|
||||
|
37
crates/ruma-events-macros/src/util.rs
Normal file
37
crates/ruma-events-macros/src/util.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use crate::event_parse::{EventKind, EventKindVariation};
|
||||
|
||||
pub(crate) fn is_non_stripped_room_event(kind: EventKind, var: EventKindVariation) -> bool {
|
||||
matches!(kind, EventKind::Message | EventKind::State)
|
||||
&& matches!(
|
||||
var,
|
||||
EventKindVariation::Full
|
||||
| EventKindVariation::Sync
|
||||
| EventKindVariation::Redacted
|
||||
| EventKindVariation::RedactedSync
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn has_prev_content_field(kind: EventKind, var: EventKindVariation) -> bool {
|
||||
matches!(kind, EventKind::State)
|
||||
&& matches!(var, EventKindVariation::Full | EventKindVariation::Sync)
|
||||
}
|
||||
|
||||
pub(crate) type EventKindFn = fn(EventKind, EventKindVariation) -> bool;
|
||||
|
||||
/// This const is used to generate the accessor methods for the `Any*Event` enums.
|
||||
///
|
||||
/// DO NOT alter the field names unless the structs in `ruma_events::event_kinds` have changed.
|
||||
pub(crate) const EVENT_FIELDS: &[(&str, EventKindFn)] = &[
|
||||
("origin_server_ts", is_non_stripped_room_event),
|
||||
("room_id", |kind, var| {
|
||||
matches!(kind, EventKind::Message | EventKind::State | EventKind::Ephemeral)
|
||||
&& matches!(var, EventKindVariation::Full | EventKindVariation::Redacted)
|
||||
}),
|
||||
("event_id", is_non_stripped_room_event),
|
||||
("sender", |kind, var| {
|
||||
matches!(kind, EventKind::Message | EventKind::State | EventKind::ToDevice)
|
||||
&& var != EventKindVariation::Initial
|
||||
}),
|
||||
("state_key", |kind, _| matches!(kind, EventKind::State)),
|
||||
("unsigned", is_non_stripped_room_event),
|
||||
];
|
Loading…
x
Reference in New Issue
Block a user