events: Disallow more than one event kind attribute
… and also raise an error if there's multiple type attributes (extra ones used to be ignored).
This commit is contained in:
parent
b2b8265ded
commit
11fea54173
@ -38,18 +38,16 @@ enum EventMeta {
|
|||||||
|
|
||||||
impl EventMeta {
|
impl EventMeta {
|
||||||
fn get_event_type(&self) -> Option<&LitStr> {
|
fn get_event_type(&self) -> Option<&LitStr> {
|
||||||
if let Self::Type(lit) = self {
|
match self {
|
||||||
Some(lit)
|
Self::Type(t) => Some(t),
|
||||||
} else {
|
_ => None,
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_event_kind(&self) -> Option<&EventKind> {
|
fn get_event_kind(&self) -> Option<&EventKind> {
|
||||||
if let Self::Kind(lit) = self {
|
match self {
|
||||||
Some(lit)
|
Self::Kind(k) => Some(k),
|
||||||
} else {
|
_ => None,
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,8 +86,8 @@ impl MetaAttrs {
|
|||||||
self.0.iter().find_map(|a| a.get_event_type())
|
self.0.iter().find_map(|a| a.get_event_type())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_event_kinds(&self) -> Vec<&EventKind> {
|
fn get_event_kind(&self) -> Option<&EventKind> {
|
||||||
self.0.iter().filter_map(|a| a.get_event_kind()).collect()
|
self.0.iter().find_map(|a| a.get_event_kind())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,19 +116,41 @@ pub fn expand_event_content(
|
|||||||
.map(|attr| attr.parse_args::<MetaAttrs>())
|
.map(|attr| attr.parse_args::<MetaAttrs>())
|
||||||
.collect::<syn::Result<Vec<_>>>()?;
|
.collect::<syn::Result<Vec<_>>>()?;
|
||||||
|
|
||||||
let event_type = content_attr.iter().find_map(|a| a.get_event_type()).ok_or_else(|| {
|
let mut event_types: Vec<_> =
|
||||||
let msg = "no event type attribute found, \
|
content_attr.iter().filter_map(|attrs| attrs.get_event_type()).collect();
|
||||||
|
let event_type = match event_types.as_slice() {
|
||||||
|
[] => {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
Span::call_site(),
|
||||||
|
"no event type attribute found, \
|
||||||
add `#[ruma_event(type = \"any.room.event\", kind = Kind)]` \
|
add `#[ruma_event(type = \"any.room.event\", kind = Kind)]` \
|
||||||
below the event content derive";
|
below the event content derive",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
[_] => event_types.pop().unwrap(),
|
||||||
|
_ => {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
Span::call_site(),
|
||||||
|
"multiple event type attribute found, there can only be one",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
syn::Error::new(Span::call_site(), msg)
|
let mut event_kinds: Vec<_> =
|
||||||
})?;
|
content_attr.iter().filter_map(|attrs| attrs.get_event_kind()).collect();
|
||||||
|
let event_kind = match event_kinds.as_slice() {
|
||||||
let content_derives =
|
[] => None,
|
||||||
content_attr.iter().flat_map(|args| args.get_event_kinds()).collect::<Vec<_>>();
|
[_] => Some(event_kinds.pop().unwrap()),
|
||||||
|
_ => {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
Span::call_site(),
|
||||||
|
"multiple event kind attribute found, there can only be one",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// We only generate redacted content structs for state and message events
|
// We only generate redacted content structs for state and message events
|
||||||
let redacted = if needs_redacted(&content_attr, &content_derives) {
|
let redacted = if needs_redacted(&content_attr, event_kind) {
|
||||||
let doc = format!("The payload for a redacted `{}`", ident);
|
let doc = format!("The payload for a redacted `{}`", ident);
|
||||||
let redacted_ident = format_ident!("Redacted{}", ident);
|
let redacted_ident = format_ident!("Redacted{}", ident);
|
||||||
let kept_redacted_fields = if let syn::Data::Struct(syn::DataStruct {
|
let kept_redacted_fields = if let syn::Data::Struct(syn::DataStruct {
|
||||||
@ -221,20 +241,17 @@ pub fn expand_event_content(
|
|||||||
let redacted_event_content =
|
let redacted_event_content =
|
||||||
generate_event_content_impl(&redacted_ident, event_type, ruma_events);
|
generate_event_content_impl(&redacted_ident, event_type, ruma_events);
|
||||||
|
|
||||||
let redacted_event_content_derive = content_derives
|
let redacted_event_content_derive = match event_kind {
|
||||||
.iter()
|
Some(EventKind::Message) => quote! {
|
||||||
.map(|kind| match kind {
|
|
||||||
EventKind::Message => quote! {
|
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #ruma_events::RedactedMessageEventContent for #redacted_ident {}
|
impl #ruma_events::RedactedMessageEventContent for #redacted_ident {}
|
||||||
},
|
},
|
||||||
EventKind::State => quote! {
|
Some(EventKind::State) => quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #ruma_events::RedactedStateEventContent for #redacted_ident {}
|
impl #ruma_events::RedactedStateEventContent for #redacted_ident {}
|
||||||
},
|
},
|
||||||
_ => TokenStream::new(),
|
_ => TokenStream::new(),
|
||||||
})
|
};
|
||||||
.collect::<TokenStream>();
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
// this is the non redacted event content's impl
|
// this is the non redacted event content's impl
|
||||||
@ -286,7 +303,7 @@ pub fn expand_event_content(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let event_content_derive =
|
let event_content_derive =
|
||||||
generate_event_content_derives(&content_derives, ident, ruma_events)?;
|
event_kind.map(|k| generate_event_content_derive(k, ident, ruma_events)).transpose()?;
|
||||||
|
|
||||||
let event_content = generate_event_content_impl(ident, event_type, ruma_events);
|
let event_content = generate_event_content_impl(ident, event_type, ruma_events);
|
||||||
|
|
||||||
@ -297,33 +314,30 @@ pub fn expand_event_content(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_event_content_derives(
|
fn generate_event_content_derive(
|
||||||
content_attr: &[&EventKind],
|
event_kind: &EventKind,
|
||||||
ident: &Ident,
|
ident: &Ident,
|
||||||
ruma_events: &TokenStream,
|
ruma_events: &TokenStream,
|
||||||
) -> syn::Result<TokenStream> {
|
) -> syn::Result<TokenStream> {
|
||||||
let msg = "valid event kinds are GlobalAccountData, RoomAccountData, \
|
let marker_trait = match event_kind {
|
||||||
EphemeralRoom, Message, State, ToDevice";
|
EventKind::GlobalAccountData => quote! { GlobalAccountDataEventContent },
|
||||||
let marker_traits: Vec<_> = content_attr
|
EventKind::RoomAccountData => quote! { RoomAccountDataEventContent },
|
||||||
.iter()
|
EventKind::Ephemeral => quote! { EphemeralRoomEventContent },
|
||||||
.map(|kind| match kind {
|
EventKind::Message => quote! { MessageEventContent },
|
||||||
EventKind::GlobalAccountData => Ok(quote! { GlobalAccountDataEventContent }),
|
EventKind::State => quote! { StateEventContent },
|
||||||
EventKind::RoomAccountData => Ok(quote! { RoomAccountDataEventContent }),
|
EventKind::ToDevice => quote! { ToDeviceEventContent },
|
||||||
EventKind::Ephemeral => Ok(quote! { EphemeralRoomEventContent }),
|
|
||||||
EventKind::Message => Ok(quote! { MessageEventContent }),
|
|
||||||
EventKind::State => Ok(quote! { StateEventContent }),
|
|
||||||
EventKind::ToDevice => Ok(quote! { ToDeviceEventContent }),
|
|
||||||
EventKind::Redaction | EventKind::Presence | EventKind::Decrypted => {
|
EventKind::Redaction | EventKind::Presence | EventKind::Decrypted => {
|
||||||
Err(syn::Error::new_spanned(ident, msg))
|
return Err(syn::Error::new_spanned(
|
||||||
|
ident,
|
||||||
|
"valid event kinds are GlobalAccountData, RoomAccountData, \
|
||||||
|
EphemeralRoom, Message, State, ToDevice",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
})
|
};
|
||||||
.collect::<syn::Result<_>>()?;
|
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#(
|
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
impl #ruma_events::#marker_traits for #ident {}
|
impl #ruma_events::#marker_trait for #ident {}
|
||||||
)*
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,10 +372,10 @@ fn generate_event_content_impl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn needs_redacted(input: &[MetaAttrs], content_derives: &[&EventKind]) -> bool {
|
fn needs_redacted(input: &[MetaAttrs], event_kind: Option<&EventKind>) -> bool {
|
||||||
// `is_custom` means that the content struct does not need a generated
|
// `is_custom` means that the content struct does not need a generated
|
||||||
// redacted struct also. If no `custom_redacted` attrs are found the content
|
// redacted struct also. If no `custom_redacted` attrs are found the content
|
||||||
// needs a redacted struct generated.
|
// needs a redacted struct generated.
|
||||||
!input.iter().any(|a| a.is_custom())
|
!input.iter().any(|a| a.is_custom())
|
||||||
&& content_derives.iter().any(|e| e.is_message() || e.is_state())
|
&& matches!(event_kind, Some(EventKind::Message) | Some(EventKind::State))
|
||||||
}
|
}
|
||||||
|
@ -324,22 +324,28 @@ fn expand_any_redacted(
|
|||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
use EventKindVariation as V;
|
use EventKindVariation as V;
|
||||||
|
|
||||||
if kind.is_state() {
|
match kind {
|
||||||
|
EventKind::State => {
|
||||||
let full_state =
|
let full_state =
|
||||||
expand_any_with_deser(kind, events, attrs, variants, &V::Redacted, ruma_events);
|
expand_any_with_deser(kind, events, attrs, variants, &V::Redacted, ruma_events);
|
||||||
let sync_state =
|
let sync_state =
|
||||||
expand_any_with_deser(kind, events, attrs, variants, &V::RedactedSync, ruma_events);
|
expand_any_with_deser(kind, events, attrs, variants, &V::RedactedSync, ruma_events);
|
||||||
let stripped_state =
|
let stripped_state = expand_any_with_deser(
|
||||||
expand_any_with_deser(kind, events, attrs, variants, &V::RedactedStripped, ruma_events);
|
kind,
|
||||||
|
events,
|
||||||
|
attrs,
|
||||||
|
variants,
|
||||||
|
&V::RedactedStripped,
|
||||||
|
ruma_events,
|
||||||
|
);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#full_state
|
#full_state
|
||||||
|
|
||||||
#sync_state
|
#sync_state
|
||||||
|
|
||||||
#stripped_state
|
#stripped_state
|
||||||
}
|
}
|
||||||
} else if kind.is_message() {
|
}
|
||||||
|
EventKind::Message => {
|
||||||
let full_message =
|
let full_message =
|
||||||
expand_any_with_deser(kind, events, attrs, variants, &V::Redacted, ruma_events);
|
expand_any_with_deser(kind, events, attrs, variants, &V::Redacted, ruma_events);
|
||||||
let sync_message =
|
let sync_message =
|
||||||
@ -347,11 +353,10 @@ fn expand_any_redacted(
|
|||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#full_message
|
#full_message
|
||||||
|
|
||||||
#sync_message
|
#sync_message
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
TokenStream::new()
|
_ => TokenStream::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +438,7 @@ fn expand_content_enum(
|
|||||||
|
|
||||||
let marker_trait_impl = marker_trait(kind, ruma_events);
|
let marker_trait_impl = marker_trait(kind, ruma_events);
|
||||||
|
|
||||||
let redacted_content_enum = if kind.is_state() || kind.is_message() {
|
let redacted_content_enum = matches!(kind, EventKind::State | EventKind::Message).then(|| {
|
||||||
let redacted_ident = kind.to_redacted_content_enum();
|
let redacted_ident = kind.to_redacted_content_enum();
|
||||||
let redaction_variants = variants.iter().map(|v| v.ctor(&redacted_ident));
|
let redaction_variants = variants.iter().map(|v| v.ctor(&redacted_ident));
|
||||||
let redacted_content: Vec<_> = events
|
let redacted_content: Vec<_> = events
|
||||||
@ -482,17 +487,12 @@ fn expand_content_enum(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
});
|
||||||
TokenStream::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#content_enum
|
#content_enum
|
||||||
|
|
||||||
#event_content_impl
|
#event_content_impl
|
||||||
|
|
||||||
#marker_trait_impl
|
#marker_trait_impl
|
||||||
|
|
||||||
#redacted_content_enum
|
#redacted_content_enum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,14 +111,6 @@ impl IdentFragment for EventKindVariation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EventKind {
|
impl EventKind {
|
||||||
pub fn is_state(&self) -> bool {
|
|
||||||
matches!(self, Self::State)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_message(&self) -> bool {
|
|
||||||
matches!(self, Self::Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_event_ident(&self, var: &EventKindVariation) -> Option<Ident> {
|
pub fn to_event_ident(&self, var: &EventKindVariation) -> Option<Ident> {
|
||||||
use EventKindVariation as V;
|
use EventKindVariation as V;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user