Derive Serialize in ruma_events!, use json EventType string for event_type field

Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
This commit is contained in:
Ragotzy.devin 2020-03-24 09:25:50 -04:00 committed by GitHub
parent 14df832005
commit 8ea971b082
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 67 additions and 80 deletions

View File

@ -1,5 +1,4 @@
//! Details of generating code for the `ruma_event` procedural macro. //! Details of generating code for the `ruma_event` procedural macro.
use proc_macro2::{Span, TokenStream}; use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote, quote_spanned, ToTokens}; use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::{ use syn::{
@ -7,7 +6,7 @@ use syn::{
parse_quote, parse_quote,
punctuated::Punctuated, punctuated::Punctuated,
spanned::Spanned, spanned::Spanned,
Attribute, Field, Ident, Path, Token, Type, Attribute, Field, Ident, LitStr, Token, Type,
}; };
use crate::parse::{Content, EventKind, RumaEventInput}; use crate::parse::{Content, EventKind, RumaEventInput};
@ -25,7 +24,7 @@ pub struct RumaEvent {
/// The variant of `ruma_events::EventType` for this event, determined by the `event_type` /// The variant of `ruma_events::EventType` for this event, determined by the `event_type`
/// field. /// field.
event_type: Path, event_type: LitStr,
/// Struct fields of the event. /// Struct fields of the event.
fields: Vec<Field>, fields: Vec<Field>,
@ -80,10 +79,12 @@ impl ToTokens for RumaEvent {
let content_name = &self.content_name; let content_name = &self.content_name;
let event_fields = &self.fields; let event_fields = &self.fields;
let event_type = { let event_type_variant = {
let event_type = &self.event_type; let event_type = to_camel_case(self.event_type.value());
let variant = Ident::new(&event_type, event_type.span());
quote! { quote! {
#event_type ::ruma_events::EventType::#variant
} }
}; };
@ -315,7 +316,7 @@ impl ToTokens for RumaEvent {
/// The type of the event. /// The type of the event.
fn event_type(&self) -> ::ruma_events::EventType { fn event_type(&self) -> ::ruma_events::EventType {
#event_type #event_type_variant
} }
} }
@ -406,6 +407,16 @@ fn is_option(ty: &Type) -> bool {
} }
} }
/// Splits the given `event_type` string on `.` and `_` removing the `m.` then
/// camel casing to give the `EventType` variant.
fn to_camel_case(name: String) -> String {
assert_eq!(&name[..2], "m.");
name[2..]
.split(&['.', '_'] as &[char])
.map(|s| s.chars().next().unwrap().to_uppercase().to_string() + &s[1..])
.collect()
}
/// A wrapper around `syn::Field` that makes it possible to parse `Punctuated<Field, Token![,]>` /// A wrapper around `syn::Field` that makes it possible to parse `Punctuated<Field, Token![,]>`
/// from a `TokenStream`. /// from a `TokenStream`.
/// ///

View File

@ -1,14 +1,10 @@
//! Details of parsing input for the `ruma_event` procedural macro. //! Details of parsing input for the `ruma_event` procedural macro.
use proc_macro2::Span;
use syn::{ use syn::{
braced, braced,
parse::{self, Parse, ParseStream}, parse::{self, Parse, ParseStream},
punctuated::Punctuated,
token::Colon, token::Colon,
Attribute, Expr, Field, FieldValue, Ident, Member, Path, PathArguments, PathSegment, Token, Attribute, Expr, ExprLit, Field, FieldValue, Ident, Lit, LitStr, Member, Token, TypePath,
TypePath,
}; };
/// The entire `ruma_event!` macro structure directly as it appears in the source code.. /// The entire `ruma_event!` macro structure directly as it appears in the source code..
@ -22,9 +18,11 @@ pub struct RumaEventInput {
/// The kind of event, determiend by the `kind` field. /// The kind of event, determiend by the `kind` field.
pub kind: EventKind, pub kind: EventKind,
/// The variant of `ruma_events::EventType` for this event, determined by the `event_type` /// The value for the `type` field in the JSON representation of this event. There needs to be a
/// field. /// corresponding variant in `ruma_events::EventType` for this event (converted to a valid
pub event_type: Path, /// Rust-style type name by stripping `m.`, replacing the remaining dots by underscores and then
/// converting from snake_case to CamelCase).
pub event_type: LitStr,
/// Additional named struct fields in the top level event struct. /// Additional named struct fields in the top level event struct.
pub fields: Option<Vec<Field>>, pub fields: Option<Vec<Field>>,
@ -98,35 +96,13 @@ impl Parse for RumaEventInput {
kind = Some(event_kind); kind = Some(event_kind);
} else if ident == "event_type" { } else if ident == "event_type" {
match field_value.expr { event_type = Some(match field_value.expr {
Expr::Path(expr_path) => { Expr::Lit(ExprLit { lit: Lit::Str(s), .. }) => s,
if expr_path.path.segments.len() != 1 { // TODO: Span info
panic!("value of field `event_type` is required to be an ident by `ruma_event!`");
}
let path = expr_path.path;
let variant = path.segments.first().unwrap();
let mut punctuated = Punctuated::new();
punctuated.push(PathSegment {
ident: Ident::new("ruma_events", Span::call_site()),
arguments: PathArguments::None,
});
punctuated.push(PathSegment {
ident: Ident::new("EventType", Span::call_site()),
arguments: PathArguments::None,
});
punctuated.push(variant.clone());
event_type = Some(Path {
leading_colon: Some(Default::default()),
segments: punctuated,
});
}
_ => panic!( _ => panic!(
"value of field `event_type` is required to be an ident by `ruma_event!`" "value of field `event_type` is required to be a string literal by `ruma_event!`"
), ),
} })
} else { } else {
panic!("unexpected field-value pair with field name `{}`", ident); panic!("unexpected field-value pair with field name `{}`", ident);
} }

View File

@ -9,7 +9,7 @@ ruma_event! {
/// This event is sent by the callee when they wish to answer the call. /// This event is sent by the callee when they wish to answer the call.
AnswerEvent { AnswerEvent {
kind: RoomEvent, kind: RoomEvent,
event_type: CallAnswer, event_type: "m.call.answer",
content: { content: {
/// The VoIP session description object. The session description type must be *answer*. /// The VoIP session description object. The session description type must be *answer*.
pub answer: SessionDescription, pub answer: SessionDescription,

View File

@ -10,7 +10,7 @@ ruma_event! {
/// communicate. /// communicate.
CandidatesEvent { CandidatesEvent {
kind: RoomEvent, kind: RoomEvent,
event_type: CallCandidates, event_type: "m.call.candidates",
content: { content: {
/// The ID of the call this event relates to. /// The ID of the call this event relates to.
pub call_id: String, pub call_id: String,

View File

@ -9,7 +9,7 @@ ruma_event! {
/// the call has has been established or before to abort the call. /// the call has has been established or before to abort the call.
HangupEvent { HangupEvent {
kind: RoomEvent, kind: RoomEvent,
event_type: CallHangup, event_type: "m.call.hangup",
content: { content: {
/// The ID of the call this event relates to. /// The ID of the call this event relates to.
pub call_id: String, pub call_id: String,

View File

@ -9,7 +9,7 @@ ruma_event! {
/// This event is sent by the caller when they wish to establish a call. /// This event is sent by the caller when they wish to establish a call.
InviteEvent { InviteEvent {
kind: RoomEvent, kind: RoomEvent,
event_type: CallInvite, event_type: "m.call.invite",
content: { content: {
/// A unique identifer for the call. /// A unique identifer for the call.
pub call_id: String, pub call_id: String,

View File

@ -9,7 +9,7 @@ ruma_event! {
/// Informs the client about the rooms that are considered direct by a user. /// Informs the client about the rooms that are considered direct by a user.
DirectEvent { DirectEvent {
kind: Event, kind: Event,
event_type: Direct, event_type: "m.direct",
content_type_alias: { content_type_alias: {
/// The payload for `DirectEvent`. /// The payload for `DirectEvent`.
/// ///

View File

@ -16,7 +16,7 @@ ruma_event! {
/// sending client receiving keys over the newly established session. /// sending client receiving keys over the newly established session.
DummyEvent { DummyEvent {
kind: Event, kind: Event,
event_type: Dummy, event_type: "m.dummy",
content_type_alias: { content_type_alias: {
/// The payload for `DummyEvent`. /// The payload for `DummyEvent`.
Empty Empty

View File

@ -11,7 +11,7 @@ ruma_event! {
/// Typically it is encrypted as an *m.room.encrypted* event, then sent as a to-device event. /// Typically it is encrypted as an *m.room.encrypted* event, then sent as a to-device event.
ForwardedRoomKeyEvent { ForwardedRoomKeyEvent {
kind: Event, kind: Event,
event_type: ForwardedRoomKey, event_type: "m.forwarded_room_key",
content: { content: {
/// The encryption algorithm the key in this event is to be used with. /// The encryption algorithm the key in this event is to be used with.
pub algorithm: Algorithm, pub algorithm: Algorithm,

View File

@ -10,7 +10,7 @@ ruma_event! {
/// for. /// for.
FullyReadEvent { FullyReadEvent {
kind: Event, kind: Event,
event_type: FullyRead, event_type: "m.fully_read",
fields: { fields: {
/// The unique identifier for the room associated with this event. /// The unique identifier for the room associated with this event.
/// ///

View File

@ -13,7 +13,7 @@ ruma_event! {
/// Typically sent as a to-device event. /// Typically sent as a to-device event.
AcceptEvent { AcceptEvent {
kind: Event, kind: Event,
event_type: KeyVerificationAccept, event_type: "m.key.verification.accept",
content: { content: {
/// An opaque identifier for the verification process. /// An opaque identifier for the verification process.
/// ///

View File

@ -14,7 +14,7 @@ ruma_event! {
/// Typically sent as a to-device event. /// Typically sent as a to-device event.
CancelEvent { CancelEvent {
kind: Event, kind: Event,
event_type: KeyVerificationCancel, event_type: "m.key.verification.cancel",
content: { content: {
/// The opaque identifier for the verification process/request. /// The opaque identifier for the verification process/request.
pub transaction_id: String, pub transaction_id: String,

View File

@ -8,7 +8,7 @@ ruma_event! {
/// Typically sent as a to-device event. /// Typically sent as a to-device event.
KeyEvent { KeyEvent {
kind: Event, kind: Event,
event_type: KeyVerificationKey, event_type: "m.key.verification.key",
content: { content: {
/// An opaque identifier for the verification process. /// An opaque identifier for the verification process.
/// ///

View File

@ -10,7 +10,7 @@ ruma_event! {
/// Typically sent as a to-device event. /// Typically sent as a to-device event.
MacEvent { MacEvent {
kind: Event, kind: Event,
event_type: KeyVerificationMac, event_type: "m.key.verification.mac",
content: { content: {
/// An opaque identifier for the verification process. /// An opaque identifier for the verification process.
/// ///

View File

@ -12,7 +12,7 @@ ruma_event! {
/// Typically sent as a to-device event. /// Typically sent as a to-device event.
RequestEvent { RequestEvent {
kind: Event, kind: Event,
event_type: KeyVerificationRequest, event_type: "m.key.verification.request",
content: { content: {
/// The device ID which is initiating the request. /// The device ID which is initiating the request.
pub from_device: DeviceId, pub from_device: DeviceId,

View File

@ -9,7 +9,7 @@ ruma_event! {
/// Informs the client of a user's presence state change. /// Informs the client of a user's presence state change.
PresenceEvent { PresenceEvent {
kind: Event, kind: Event,
event_type: Presence, event_type: "m.presence",
fields: { fields: {
/// The unique identifier for the user associated with this event. /// The unique identifier for the user associated with this event.
pub sender: UserId, pub sender: UserId,

View File

@ -19,7 +19,7 @@ ruma_event! {
/// Describes all push rules for a user. /// Describes all push rules for a user.
PushRulesEvent { PushRulesEvent {
kind: Event, kind: Event,
event_type: PushRules, event_type: "m.push_rules",
content: { content: {
/// The global ruleset. /// The global ruleset.
pub global: Ruleset, pub global: Ruleset,

View File

@ -11,7 +11,7 @@ ruma_event! {
/// Informs the client of new receipts. /// Informs the client of new receipts.
ReceiptEvent { ReceiptEvent {
kind: Event, kind: Event,
event_type: Receipt, event_type: "m.receipt",
fields: { fields: {
/// The unique identifier for the room associated with this event. /// The unique identifier for the room associated with this event.
/// ///

View File

@ -7,7 +7,7 @@ ruma_event! {
/// Informs the room about what room aliases it has been given. /// Informs the room about what room aliases it has been given.
AliasesEvent { AliasesEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomAliases, event_type: "m.room.aliases",
content: { content: {
/// A list of room aliases. /// A list of room aliases.
pub aliases: Vec<RoomAliasId>, pub aliases: Vec<RoomAliasId>,

View File

@ -10,7 +10,7 @@ ruma_event! {
/// This can be displayed alongside the room information. /// This can be displayed alongside the room information.
AvatarEvent { AvatarEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomAvatar, event_type: "m.room.avatar",
content: { content: {
/// Information about the avatar image. /// Information about the avatar image.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]

View File

@ -13,7 +13,7 @@ ruma_event! {
/// events. /// events.
CreateEvent { CreateEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomCreate, event_type: "m.room.create",
content: { content: {
/// The `user_id` of the room creator. This is set by the homeserver. /// The `user_id` of the room creator. This is set by the homeserver.
pub creator: UserId, pub creator: UserId,

View File

@ -9,7 +9,7 @@ ruma_event! {
/// Defines how messages sent in this room should be encrypted. /// Defines how messages sent in this room should be encrypted.
EncryptionEvent { EncryptionEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomEncryption, event_type: "m.room.encryption",
content: { content: {
/// The encryption algorithm to be used to encrypt messages sent in this room. /// The encryption algorithm to be used to encrypt messages sent in this room.
/// ///

View File

@ -10,7 +10,7 @@ ruma_event! {
/// servers should act as if it is present and has the value `GuestAccess::Forbidden`. /// servers should act as if it is present and has the value `GuestAccess::Forbidden`.
GuestAccessEvent { GuestAccessEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomGuestAccess, event_type: "m.room.guest_access",
content: { content: {
/// A policy for guest user access to a room. /// A policy for guest user access to a room.
pub guest_access: GuestAccess, pub guest_access: GuestAccess,

View File

@ -8,7 +8,7 @@ ruma_event! {
/// from before they joined. /// from before they joined.
HistoryVisibilityEvent { HistoryVisibilityEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomHistoryVisibility, event_type: "m.room.history_visibility",
content: { content: {
/// Who can see the room history. /// Who can see the room history.
pub history_visibility: HistoryVisibility, pub history_visibility: HistoryVisibility,

View File

@ -7,7 +7,7 @@ ruma_event! {
/// Describes how users are allowed to join the room. /// Describes how users are allowed to join the room.
JoinRulesEvent { JoinRulesEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomJoinRules, event_type: "m.room.join_rules",
content: { content: {
/// The type of rules used for users wishing to join this room. /// The type of rules used for users wishing to join this room.
pub join_rule: JoinRule, pub join_rule: JoinRule,

View File

@ -34,7 +34,7 @@ ruma_event! {
/// must be assumed as leave. /// must be assumed as leave.
MemberEvent { MemberEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomMember, event_type: "m.room.member",
content: { content: {
/// The avatar URL for this user, if any. This is added by the homeserver. /// The avatar URL for this user, if any. This is added by the homeserver.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]

View File

@ -11,7 +11,7 @@ ruma_event! {
/// not recognize this event. /// not recognize this event.
FeedbackEvent { FeedbackEvent {
kind: RoomEvent, kind: RoomEvent,
event_type: RoomMessageFeedback, event_type: "m.room.message.feedback",
content: { content: {
/// The event that this feedback is related to. /// The event that this feedback is related to.
pub target_event_id: EventId, pub target_event_id: EventId,

View File

@ -7,7 +7,7 @@ ruma_event! {
/// Used to "pin" particular events in a room for other participants to review later. /// Used to "pin" particular events in a room for other participants to review later.
PinnedEventsEvent { PinnedEventsEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomPinnedEvents, event_type: "m.room.pinned_events",
content: { content: {
/// An ordered list of event IDs to pin. /// An ordered list of event IDs to pin.
pub pinned: Vec<EventId>, pub pinned: Vec<EventId>,

View File

@ -7,7 +7,7 @@ ruma_event! {
/// A redaction of an event. /// A redaction of an event.
RedactionEvent { RedactionEvent {
kind: RoomEvent, kind: RoomEvent,
event_type: RoomRedaction, event_type: "m.room.redaction",
fields: { fields: {
/// The ID of the event that was redacted. /// The ID of the event that was redacted.
pub redacts: EventId, pub redacts: EventId,

View File

@ -11,7 +11,7 @@ ruma_event! {
/// Any user who can present that signature may use this invitation to join the target room. /// Any user who can present that signature may use this invitation to join the target room.
ThirdPartyInviteEvent { ThirdPartyInviteEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomThirdPartyInvite, event_type: "m.room.third_party_invite",
content: { content: {
/// A user-readable string which represents the user who has been invited. /// A user-readable string which represents the user who has been invited.
pub display_name: String, pub display_name: String,

View File

@ -8,7 +8,7 @@ ruma_event! {
/// clients should go there. /// clients should go there.
TombstoneEvent { TombstoneEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomTombstone, event_type: "m.room.tombstone",
content: { content: {
/// A server-defined message. /// A server-defined message.
pub body: String, pub body: String,

View File

@ -6,7 +6,7 @@ ruma_event! {
/// A topic is a short message detailing what is currently being discussed in the room. /// A topic is a short message detailing what is currently being discussed in the room.
TopicEvent { TopicEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomTopic, event_type: "m.room.topic",
content: { content: {
/// The topic text. /// The topic text.
pub topic: String, pub topic: String,

View File

@ -11,7 +11,7 @@ ruma_event! {
/// Typically it is encrypted as an *m.room.encrypted* event, then sent as a to-device event. /// Typically it is encrypted as an *m.room.encrypted* event, then sent as a to-device event.
RoomKeyEvent { RoomKeyEvent {
kind: Event, kind: Event,
event_type: RoomKey, event_type: "m.room_key",
content: { content: {
/// The encryption algorithm the key in this event is to be used with. /// The encryption algorithm the key in this event is to be used with.
/// ///

View File

@ -12,7 +12,7 @@ ruma_event! {
/// It is sent as an unencrypted to-device event. /// It is sent as an unencrypted to-device event.
RoomKeyRequestEvent { RoomKeyRequestEvent {
kind: Event, kind: Event,
event_type: RoomKeyRequest, event_type: "m.room_key_request",
content: { content: {
/// Whether this is a new key request or a cancellation of a previous request. /// Whether this is a new key request or a cancellation of a previous request.
pub action: Action, pub action: Action,

View File

@ -8,7 +8,7 @@ ruma_event! {
/// A sticker message. /// A sticker message.
StickerEvent { StickerEvent {
kind: RoomEvent, kind: RoomEvent,
event_type: Sticker, event_type: "m.sticker",
content: { content: {
/// A textual representation or associated description of the sticker image. This could /// A textual representation or associated description of the sticker image. This could
/// be the alt text of the original image, or a message to accompany and further /// be the alt text of the original image, or a message to accompany and further

View File

@ -9,7 +9,7 @@ ruma_event! {
/// Informs the client of tags on a room. /// Informs the client of tags on a room.
TagEvent { TagEvent {
kind: Event, kind: Event,
event_type: Tag, event_type: "m.tag",
content: { content: {
/// A map of tag names to tag info. /// A map of tag names to tag info.
pub tags: HashMap<String, TagInfo>, pub tags: HashMap<String, TagInfo>,

View File

@ -7,7 +7,7 @@ ruma_event! {
/// Informs the client of the list of users currently typing. /// Informs the client of the list of users currently typing.
TypingEvent { TypingEvent {
kind: Event, kind: Event,
event_type: Typing, event_type: "m.typing",
fields: { fields: {
/// The unique identifier for the room associated with this event. /// The unique identifier for the room associated with this event.
/// ///

View File

@ -14,7 +14,7 @@ mod common_case {
/// Informs the room about what room aliases it has been given. /// Informs the room about what room aliases it has been given.
AliasesEvent { AliasesEvent {
kind: StateEvent, kind: StateEvent,
event_type: RoomAliases, event_type: "m.room.aliases",
content: { content: {
/// A list of room aliases. /// A list of room aliases.
pub aliases: Vec<ruma_identifiers::RoomAliasId>, pub aliases: Vec<ruma_identifiers::RoomAliasId>,
@ -126,7 +126,7 @@ mod extra_fields {
/// A redaction of an event. /// A redaction of an event.
RedactionEvent { RedactionEvent {
kind: RoomEvent, kind: RoomEvent,
event_type: RoomRedaction, event_type: "m.room.redaction",
fields: { fields: {
/// The ID of the event that was redacted. /// The ID of the event that was redacted.
pub redacts: ruma_identifiers::EventId pub redacts: ruma_identifiers::EventId
@ -174,7 +174,7 @@ mod type_alias {
/// Informs the client about the rooms that are considered direct by a user. /// Informs the client about the rooms that are considered direct by a user.
DirectEvent { DirectEvent {
kind: Event, kind: Event,
event_type: Direct, event_type: "m.direct",
content_type_alias: { content_type_alias: {
/// The payload of a `DirectEvent`. /// The payload of a `DirectEvent`.
/// ///