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 { 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::>>()?; let content = input.events.iter().map(to_event_path).collect::>(); @@ -26,6 +27,8 @@ pub fn expand_event_enum(input: EventEnumInput) -> syn::Result { #[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 { 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 { #[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 event must satisfy all of the event content marker traits since +// they can be used for any event kind. +impl RoomEventContent for CustomEventContent {} -/// A custom message event not covered by the Matrix specification. -#[derive(Clone, Debug)] -pub struct CustomMessageEvent { - /// The event's content. - pub content: CustomEventContent, +impl BasicEventContent for CustomEventContent {} - /// Time on originating homeserver when this event was sent. - pub origin_server_ts: SystemTime, +impl EphemeralRoomEventContent for CustomEventContent {} - /// The unique identifier for the room associated with this event. - pub room_id: Option, +impl MessageEventContent for CustomEventContent {} - /// 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, -} - -/// A custom state event not covered by the Matrix specification. -#[derive(Clone, Debug)] -pub struct CustomStateEvent { - /// The event's content. - pub content: CustomEventContent, - - /// The unique identifier for the event. - pub event_id: EventId, - - /// 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, - - /// The unique identifier for the room associated with this event. - pub room_id: Option, - - /// 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, 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::>>(json_data) + from_json_value::>(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", ]