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 {
|
||||
fn get_event_type(&self) -> Option<&LitStr> {
|
||||
if let Self::Type(lit) = self {
|
||||
Some(lit)
|
||||
} else {
|
||||
None
|
||||
match self {
|
||||
Self::Type(t) => Some(t),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_event_kind(&self) -> Option<&EventKind> {
|
||||
if let Self::Kind(lit) = self {
|
||||
Some(lit)
|
||||
} else {
|
||||
None
|
||||
match self {
|
||||
Self::Kind(k) => Some(k),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,8 +86,8 @@ impl MetaAttrs {
|
||||
self.0.iter().find_map(|a| a.get_event_type())
|
||||
}
|
||||
|
||||
fn get_event_kinds(&self) -> Vec<&EventKind> {
|
||||
self.0.iter().filter_map(|a| a.get_event_kind()).collect()
|
||||
fn get_event_kind(&self) -> Option<&EventKind> {
|
||||
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>())
|
||||
.collect::<syn::Result<Vec<_>>>()?;
|
||||
|
||||
let event_type = content_attr.iter().find_map(|a| a.get_event_type()).ok_or_else(|| {
|
||||
let msg = "no event type attribute found, \
|
||||
let mut event_types: Vec<_> =
|
||||
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)]` \
|
||||
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 content_derives =
|
||||
content_attr.iter().flat_map(|args| args.get_event_kinds()).collect::<Vec<_>>();
|
||||
let mut event_kinds: Vec<_> =
|
||||
content_attr.iter().filter_map(|attrs| attrs.get_event_kind()).collect();
|
||||
let event_kind = match event_kinds.as_slice() {
|
||||
[] => None,
|
||||
[_] => 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
|
||||
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 redacted_ident = format_ident!("Redacted{}", ident);
|
||||
let kept_redacted_fields = if let syn::Data::Struct(syn::DataStruct {
|
||||
@ -221,20 +241,17 @@ pub fn expand_event_content(
|
||||
let redacted_event_content =
|
||||
generate_event_content_impl(&redacted_ident, event_type, ruma_events);
|
||||
|
||||
let redacted_event_content_derive = content_derives
|
||||
.iter()
|
||||
.map(|kind| match kind {
|
||||
EventKind::Message => quote! {
|
||||
let redacted_event_content_derive = match event_kind {
|
||||
Some(EventKind::Message) => quote! {
|
||||
#[automatically_derived]
|
||||
impl #ruma_events::RedactedMessageEventContent for #redacted_ident {}
|
||||
},
|
||||
EventKind::State => quote! {
|
||||
Some(EventKind::State) => quote! {
|
||||
#[automatically_derived]
|
||||
impl #ruma_events::RedactedStateEventContent for #redacted_ident {}
|
||||
},
|
||||
_ => TokenStream::new(),
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
};
|
||||
|
||||
quote! {
|
||||
// this is the non redacted event content's impl
|
||||
@ -286,7 +303,7 @@ pub fn expand_event_content(
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
@ -297,33 +314,30 @@ pub fn expand_event_content(
|
||||
})
|
||||
}
|
||||
|
||||
fn generate_event_content_derives(
|
||||
content_attr: &[&EventKind],
|
||||
fn generate_event_content_derive(
|
||||
event_kind: &EventKind,
|
||||
ident: &Ident,
|
||||
ruma_events: &TokenStream,
|
||||
) -> syn::Result<TokenStream> {
|
||||
let msg = "valid event kinds are GlobalAccountData, RoomAccountData, \
|
||||
EphemeralRoom, Message, State, ToDevice";
|
||||
let marker_traits: Vec<_> = content_attr
|
||||
.iter()
|
||||
.map(|kind| match kind {
|
||||
EventKind::GlobalAccountData => Ok(quote! { GlobalAccountDataEventContent }),
|
||||
EventKind::RoomAccountData => Ok(quote! { RoomAccountDataEventContent }),
|
||||
EventKind::Ephemeral => Ok(quote! { EphemeralRoomEventContent }),
|
||||
EventKind::Message => Ok(quote! { MessageEventContent }),
|
||||
EventKind::State => Ok(quote! { StateEventContent }),
|
||||
EventKind::ToDevice => Ok(quote! { ToDeviceEventContent }),
|
||||
let marker_trait = match event_kind {
|
||||
EventKind::GlobalAccountData => quote! { GlobalAccountDataEventContent },
|
||||
EventKind::RoomAccountData => quote! { RoomAccountDataEventContent },
|
||||
EventKind::Ephemeral => quote! { EphemeralRoomEventContent },
|
||||
EventKind::Message => quote! { MessageEventContent },
|
||||
EventKind::State => quote! { StateEventContent },
|
||||
EventKind::ToDevice => quote! { ToDeviceEventContent },
|
||||
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! {
|
||||
#(
|
||||
#[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
|
||||
// redacted struct also. If no `custom_redacted` attrs are found the content
|
||||
// needs a redacted struct generated.
|
||||
!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 {
|
||||
use EventKindVariation as V;
|
||||
|
||||
if kind.is_state() {
|
||||
match kind {
|
||||
EventKind::State => {
|
||||
let full_state =
|
||||
expand_any_with_deser(kind, events, attrs, variants, &V::Redacted, ruma_events);
|
||||
let sync_state =
|
||||
expand_any_with_deser(kind, events, attrs, variants, &V::RedactedSync, ruma_events);
|
||||
let stripped_state =
|
||||
expand_any_with_deser(kind, events, attrs, variants, &V::RedactedStripped, ruma_events);
|
||||
let stripped_state = expand_any_with_deser(
|
||||
kind,
|
||||
events,
|
||||
attrs,
|
||||
variants,
|
||||
&V::RedactedStripped,
|
||||
ruma_events,
|
||||
);
|
||||
|
||||
quote! {
|
||||
#full_state
|
||||
|
||||
#sync_state
|
||||
|
||||
#stripped_state
|
||||
}
|
||||
} else if kind.is_message() {
|
||||
}
|
||||
EventKind::Message => {
|
||||
let full_message =
|
||||
expand_any_with_deser(kind, events, attrs, variants, &V::Redacted, ruma_events);
|
||||
let sync_message =
|
||||
@ -347,11 +353,10 @@ fn expand_any_redacted(
|
||||
|
||||
quote! {
|
||||
#full_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 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 redaction_variants = variants.iter().map(|v| v.ctor(&redacted_ident));
|
||||
let redacted_content: Vec<_> = events
|
||||
@ -482,17 +487,12 @@ fn expand_content_enum(
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TokenStream::new()
|
||||
};
|
||||
});
|
||||
|
||||
quote! {
|
||||
#content_enum
|
||||
|
||||
#event_content_impl
|
||||
|
||||
#marker_trait_impl
|
||||
|
||||
#redacted_content_enum
|
||||
}
|
||||
}
|
||||
|
@ -111,14 +111,6 @@ impl IdentFragment for EventKindVariation {
|
||||
}
|
||||
|
||||
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> {
|
||||
use EventKindVariation as V;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user