Repository: ruma/ruma
Pull request #69 (2020-06-19 12:07:43)

Add a Custom variant to Any*Event enums

jimmycuadra: Thanks very much!

Patch:
diff --git a/ruma-events-macros/src/event_enum.rs b/ruma-events-macros/src/event_enum.rs
index 8ea4049e..689c3338 100644
--- a/ruma-events-macros/src/event_enum.rs
+++ b/ruma-events-macros/src/event_enum.rs
@@ -12,6 +12,7 @@ pub fn expand_event_enum(input: EventEnumInput) -> syn::Result<TokenStream> {
     let attrs = &input.attrs;
     let ident = &input.name;
     let event_type_str = &input.events;
+    let event_struct = Ident::new(&ident.to_string().trim_start_matches("Any"), ident.span());
 
     let variants = input.events.iter().map(to_camel_case).collect::<syn::Result<Vec<_>>>()?;
     let content = input.events.iter().map(to_event_path).collect::<Vec<_>>();
@@ -26,6 +27,8 @@ pub fn expand_event_enum(input: EventEnumInput) -> syn::Result<TokenStream> {
                 #[doc = #event_type_str]
                 #variants(#content),
             )*
+            /// An event not defined by the Matrix specification
+            Custom(::ruma_events::#event_struct<::ruma_events::custom::CustomEventContent>),
         }
     };
 
@@ -46,7 +49,13 @@ pub fn expand_event_enum(input: EventEnumInput) -> syn::Result<TokenStream> {
                             Ok(#ident::#variants(event))
                         },
                     )*
-                    _ => Err(D::Error::custom(format!("event type `{}` is not a valid event", ev_type)))
+                    event => {
+                        let event =
+                            ::serde_json::from_str::<::ruma_events::#event_struct<::ruma_events::custom::CustomEventContent>>(json.get())
+                                .map_err(D::Error::custom)?;
+
+                        Ok(Self::Custom(event))
+                    },
                 }
             }
         }
@@ -82,7 +91,7 @@ pub fn expand_content_enum(input: EventEnumInput) -> syn::Result<TokenStream> {
                 #[doc = #event_type_str]
                 #variants(#content),
             )*
-            /// Any custom event.
+            /// Content of an event not defined by the Matrix specification.
             Custom(::ruma_events::custom::CustomEventContent),
         }
     };
diff --git a/ruma-events-macros/src/lib.rs b/ruma-events-macros/src/lib.rs
index 0e5b9866..aca3c288 100644
--- a/ruma-events-macros/src/lib.rs
+++ b/ruma-events-macros/src/lib.rs
@@ -27,7 +27,20 @@ mod event_enum;
 ///
 /// This macro also implements the necessary traits for the type to serialize and deserialize
 /// itself.
-// TODO more docs/example
+///
+/// # Examples
+///
+/// ```ignore
+/// use ruma_events_macros::event_enum;
+///
+/// event_enum! {
+///     name: AnyBarEvent, // `BarEvent` has to be a valid type at `::ruma_events::BarEvent`
+///     events: [
+///         "m.any.event",
+///         "m.other.event",
+///     ]
+/// }
+/// ```
 #[proc_macro]
 pub fn event_enum(input: TokenStream) -> TokenStream {
     let event_enum_input = syn::parse_macro_input!(input as EventEnumInput);
diff --git a/ruma-events/src/custom.rs b/ruma-events/src/custom.rs
index 74dd8a9f..1cc717fd 100644
--- a/ruma-events/src/custom.rs
+++ b/ruma-events/src/custom.rs
@@ -1,12 +1,12 @@
 //! Types for custom events outside of the Matrix specification.
 
-use std::time::SystemTime;
-
-use ruma_identifiers::{EventId, RoomId, UserId};
 use serde::Serialize;
 use serde_json::{value::RawValue as RawJsonValue, Value as JsonValue};
 
-use crate::{EventContent, UnsignedData};
+use crate::{
+    BasicEventContent, EphemeralRoomEventContent, EventContent, MessageEventContent,
+    RoomEventContent, StateEventContent,
+};
 
 /// A custom event's type and `content` JSON object.
 #[derive(Clone, Debug, Serialize)]
@@ -31,56 +31,14 @@ impl EventContent for CustomEventContent {
     }
 }
 
-/// A custom event not covered by the Matrix specification.
-#[derive(Clone, Debug)]
-pub struct CustomBasicEvent {
-    /// The event's content.
-    pub content: CustomEventContent,
-}
-
-/// A custom message event not covered by the Matrix specification.
-#[derive(Clone, Debug)]
-pub struct CustomMessageEvent {
-    /// The event's content.
-    pub content: CustomEventContent,
-
-    /// Time on originating homeserver when this event was sent.
-    pub origin_server_ts: SystemTime,
+// A custom event must satisfy all of the event content marker traits since
+// they can be used for any event kind.
+impl RoomEventContent for CustomEventContent {}
 
-    /// The unique identifier for the room associated with this event.
-    pub room_id: Option<RoomId>,
-
-    /// The unique identifier for the user who sent this event.
-    pub sender: UserId,
-
-    /// Additional key-value pairs not signed by the homeserver.
-    pub unsigned: UnsignedData,
-}
+impl BasicEventContent for CustomEventContent {}
 
-/// A custom state event not covered by the Matrix specification.
-#[derive(Clone, Debug)]
-pub struct CustomStateEvent {
-    /// The event's content.
-    pub content: CustomEventContent,
+impl EphemeralRoomEventContent for CustomEventContent {}
 
-    /// The unique identifier for the event.
-    pub event_id: EventId,
+impl MessageEventContent for CustomEventContent {}
 
-    /// Time on originating homeserver when this event was sent.
-    pub origin_server_ts: SystemTime,
-
-    /// The previous content for this state key, if any.
-    pub prev_content: Option<CustomEventContent>,
-
-    /// The unique identifier for the room associated with this event.
-    pub room_id: Option<RoomId>,
-
-    /// The unique identifier for the user who sent this event.
-    pub sender: UserId,
-
-    /// A key that determines which piece of room state the event represents.
-    pub state_key: String,
-
-    /// Additional key-value pairs not signed by the homeserver.
-    pub unsigned: UnsignedData,
-}
+impl StateEventContent for CustomEventContent {}
diff --git a/ruma-events/src/lib.rs b/ruma-events/src/lib.rs
index 8d3fcec5..6444b610 100644
--- a/ruma-events/src/lib.rs
+++ b/ruma-events/src/lib.rs
@@ -160,7 +160,6 @@ pub mod typing;
 
 pub use self::{
     algorithm::Algorithm,
-    custom::{CustomBasicEvent, CustomMessageEvent, CustomStateEvent},
     enums::{
         AnyBasicEvent, AnyBasicEventContent, AnyEphemeralRoomEvent, AnyEphemeralRoomEventContent,
         AnyEvent, AnyMessageEvent, AnyMessageEventContent, AnyMessageEventStub, AnyRoomEvent,


Test patch:
diff --git a/ruma-events/tests/custom.rs b/ruma-events/tests/custom.rs
index 251764f9..ee24044e 100644
--- a/ruma-events/tests/custom.rs
+++ b/ruma-events/tests/custom.rs
@@ -5,7 +5,7 @@ use std::{
 
 use matches::assert_matches;
 use ruma_events::{
-    custom::CustomEventContent, AnyMessageEventContent, AnyStateEventContent, EventJson,
+    custom::CustomEventContent, AnyMessageEvent, AnyStateEvent, AnyStateEventContent, EventJson,
     MessageEvent, StateEvent, StateEventStub, UnsignedData,
 };
 use ruma_identifiers::{EventId, RoomId, UserId};
@@ -36,8 +36,8 @@ fn custom_state_event() -> JsonValue {
 
 #[test]
 fn serialize_custom_message_event() {
-    let aliases_event = MessageEvent {
-        content: AnyMessageEventContent::Custom(CustomEventContent {
+    let aliases_event = AnyMessageEvent::Custom(MessageEvent {
+        content: CustomEventContent {
             json: json!({
                 "body": " * edited message",
                 "m.new_content": {
@@ -51,13 +51,13 @@ fn serialize_custom_message_event() {
                 "msgtype": "m.text"
             }),
             event_type: "m.room.message".to_string(),
-        }),
+        },
         event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
         origin_server_ts: UNIX_EPOCH + Duration::from_millis(10),
         room_id: RoomId::try_from("!room:room.com").unwrap(),
         sender: UserId::try_from("@carl:example.com").unwrap(),
         unsigned: UnsignedData::default(),
-    };
+    });
 
     let actual = to_json_value(&aliases_event).unwrap();
     let expected = json!({
@@ -85,13 +85,13 @@ fn serialize_custom_message_event() {
 
 #[test]
 fn serialize_custom_state_event() {
-    let aliases_event = StateEvent {
-        content: AnyStateEventContent::Custom(CustomEventContent {
+    let aliases_event = AnyStateEvent::Custom(StateEvent {
+        content: CustomEventContent {
             json: json!({
                 "custom": 10
             }),
             event_type: "m.made.up".to_string(),
-        }),
+        },
         event_id: EventId::try_from("$h29iv0s8:example.com").unwrap(),
         origin_server_ts: UNIX_EPOCH + Duration::from_millis(10),
         prev_content: None,
@@ -99,7 +99,7 @@ fn serialize_custom_state_event() {
         sender: UserId::try_from("@carl:example.com").unwrap(),
         state_key: "".to_string(),
         unsigned: UnsignedData::default(),
-    };
+    });
 
     let actual = to_json_value(&aliases_event).unwrap();
     let expected = json!({
@@ -130,14 +130,14 @@ fn deserialize_custom_state_event() {
     });
 
     assert_matches!(
-        from_json_value::<EventJson<StateEvent<AnyStateEventContent>>>(json_data)
+        from_json_value::<EventJson<AnyStateEvent>>(json_data)
             .unwrap()
             .deserialize()
             .unwrap(),
-        StateEvent {
-            content: AnyStateEventContent::Custom(CustomEventContent {
+        AnyStateEvent::Custom(StateEvent {
+            content: CustomEventContent {
                 json, event_type,
-            }),
+            },
             event_id,
             origin_server_ts,
             sender,
@@ -145,7 +145,7 @@ fn deserialize_custom_state_event() {
             prev_content: None,
             state_key,
             unsigned,
-        } if json == expected_content && event_type == "m.reaction"
+        }) if json == expected_content && event_type == "m.reaction"
             && event_id == EventId::try_from("$h29iv0s8:example.com").unwrap()
             && origin_server_ts == UNIX_EPOCH + Duration::from_millis(10)
             && sender == UserId::try_from("@carl:example.com").unwrap()
diff --git a/ruma-events/tests/ui/08-enum-invalid-path.rs b/ruma-events/tests/ui/08-enum-invalid-path.rs
index 410b7efc..14a403a8 100644
--- a/ruma-events/tests/ui/08-enum-invalid-path.rs
+++ b/ruma-events/tests/ui/08-enum-invalid-path.rs
@@ -1,14 +1,14 @@
 use ruma_events_macros::event_enum;
 
 event_enum! {
-    name: InvalidEvent,
+    name: AnyStateEvent,
     events: [
         "m.not.a.path",
     ]
 }
 
 event_enum! {
-    name: InvalidEvent,
+    name: AnyStateEvent,
     events: [
         "not.a.path",
     ]