ruma_events/
enums.rs

1use ruma_common::{
2    serde::from_raw_json_value, EventId, MilliSecondsSinceUnixEpoch, OwnedRoomId, RoomId,
3    TransactionId, UserId,
4};
5use ruma_macros::{event_enum, EventEnumFromEvent};
6use serde::{de, Deserialize};
7use serde_json::value::RawValue as RawJsonValue;
8
9use super::room::encrypted;
10
11event_enum! {
12    /// Any global account data event.
13    enum GlobalAccountData {
14        "m.direct" => super::direct,
15        "m.identity_server" => super::identity_server,
16        "m.ignored_user_list" => super::ignored_user_list,
17        "m.push_rules" => super::push_rules,
18        "m.secret_storage.default_key" => super::secret_storage::default_key,
19        "m.secret_storage.key.*" => super::secret_storage::key,
20        #[cfg(feature = "unstable-msc2545")]
21        #[ruma_enum(ident = AccountImagePack, alias = "m.image_pack")]
22        "im.ponies.user_emotes" => super::image_pack,
23        #[cfg(feature = "unstable-msc2545")]
24        #[ruma_enum(ident = ImagePackRooms, alias = "m.image_pack.rooms")]
25        "im.ponies.emote_rooms" => super::image_pack,
26    }
27
28    /// Any room account data event.
29    enum RoomAccountData {
30        "m.fully_read" => super::fully_read,
31        "m.tag" => super::tag,
32        "m.marked_unread" => super::marked_unread,
33        #[cfg(feature = "unstable-msc2867")]
34        #[ruma_enum(ident = UnstableMarkedUnread)]
35        "com.famedly.marked_unread" => super::marked_unread,
36    }
37
38    /// Any ephemeral room event.
39    enum EphemeralRoom {
40        "m.receipt" => super::receipt,
41        "m.typing" => super::typing,
42    }
43
44    /// Any message-like event.
45    enum MessageLike {
46        #[cfg(feature = "unstable-msc3927")]
47        #[ruma_enum(alias = "m.audio")]
48        "org.matrix.msc1767.audio" => super::audio,
49        "m.call.answer" => super::call::answer,
50        "m.call.invite" => super::call::invite,
51        "m.call.hangup" => super::call::hangup,
52        "m.call.candidates" => super::call::candidates,
53        "m.call.negotiate" => super::call::negotiate,
54        "m.call.reject" => super::call::reject,
55        #[ruma_enum(alias = "org.matrix.call.sdp_stream_metadata_changed")]
56        "m.call.sdp_stream_metadata_changed" => super::call::sdp_stream_metadata_changed,
57        "m.call.select_answer" => super::call::select_answer,
58        #[cfg(feature = "unstable-msc3954")]
59        #[ruma_enum(alias = "m.emote")]
60        "org.matrix.msc1767.emote" => super::emote,
61        #[cfg(feature = "unstable-msc3956")]
62        #[ruma_enum(alias = "m.encrypted")]
63        "org.matrix.msc1767.encrypted" => super::encrypted,
64        #[cfg(feature = "unstable-msc3551")]
65        #[ruma_enum(alias = "m.file")]
66        "org.matrix.msc1767.file" => super::file,
67        #[cfg(feature = "unstable-msc3552")]
68        #[ruma_enum(alias = "m.image")]
69        "org.matrix.msc1767.image" => super::image,
70        "m.key.verification.ready" => super::key::verification::ready,
71        "m.key.verification.start" => super::key::verification::start,
72        "m.key.verification.cancel" => super::key::verification::cancel,
73        "m.key.verification.accept" => super::key::verification::accept,
74        "m.key.verification.key" => super::key::verification::key,
75        "m.key.verification.mac" => super::key::verification::mac,
76        "m.key.verification.done" => super::key::verification::done,
77        #[cfg(feature = "unstable-msc3488")]
78        "m.location" => super::location,
79        #[cfg(feature = "unstable-msc1767")]
80        #[ruma_enum(alias = "m.message")]
81        "org.matrix.msc1767.message" => super::message,
82        #[cfg(feature = "unstable-msc3381")]
83        "m.poll.start" => super::poll::start,
84        #[cfg(feature = "unstable-msc3381")]
85        #[ruma_enum(ident = UnstablePollStart)]
86        "org.matrix.msc3381.poll.start" => super::poll::unstable_start,
87        #[cfg(feature = "unstable-msc3381")]
88        "m.poll.response" => super::poll::response,
89        #[cfg(feature = "unstable-msc3381")]
90        #[ruma_enum(ident = UnstablePollResponse)]
91        "org.matrix.msc3381.poll.response" => super::poll::unstable_response,
92        #[cfg(feature = "unstable-msc3381")]
93        "m.poll.end" => super::poll::end,
94        #[cfg(feature = "unstable-msc3381")]
95        #[ruma_enum(ident = UnstablePollEnd)]
96        "org.matrix.msc3381.poll.end" => super::poll::unstable_end,
97        #[cfg(feature = "unstable-msc3489")]
98        #[ruma_enum(alias = "m.beacon")]
99        "org.matrix.msc3672.beacon" => super::beacon,
100        "m.reaction" => super::reaction,
101        "m.room.encrypted" => super::room::encrypted,
102        "m.room.message" => super::room::message,
103        "m.room.redaction" => super::room::redaction,
104        "m.sticker" => super::sticker,
105        #[cfg(feature = "unstable-msc3553")]
106        #[ruma_enum(alias = "m.video")]
107        "org.matrix.msc1767.video" => super::video,
108        #[cfg(feature = "unstable-msc3245")]
109        #[ruma_enum(alias = "m.voice")]
110        "org.matrix.msc3245.voice.v2" => super::voice,
111        #[cfg(feature = "unstable-msc4075")]
112        #[ruma_enum(alias = "m.call.notify")]
113        "org.matrix.msc4075.call.notify" => super::call::notify,
114    }
115
116    /// Any state event.
117    enum State {
118        "m.policy.rule.room" => super::policy::rule::room,
119        "m.policy.rule.server" => super::policy::rule::server,
120        "m.policy.rule.user" => super::policy::rule::user,
121        "m.room.aliases" => super::room::aliases,
122        "m.room.avatar" => super::room::avatar,
123        "m.room.canonical_alias" => super::room::canonical_alias,
124        "m.room.create" => super::room::create,
125        "m.room.encryption" => super::room::encryption,
126        "m.room.guest_access" => super::room::guest_access,
127        "m.room.history_visibility" => super::room::history_visibility,
128        "m.room.join_rules" => super::room::join_rules,
129        "m.room.member" => super::room::member,
130        "m.room.name" => super::room::name,
131        "m.room.pinned_events" => super::room::pinned_events,
132        "m.room.power_levels" => super::room::power_levels,
133        "m.room.server_acl" => super::room::server_acl,
134        "m.room.third_party_invite" => super::room::third_party_invite,
135        "m.room.tombstone" => super::room::tombstone,
136        "m.room.topic" => super::room::topic,
137        "m.space.child" => super::space::child,
138        "m.space.parent" => super::space::parent,
139        #[cfg(feature = "unstable-msc2545")]
140        #[ruma_enum(ident = RoomImagePack, alias = "m.image_pack")]
141        "im.ponies.room_emotes" => super::image_pack,
142        #[cfg(feature = "unstable-msc3489")]
143        #[ruma_enum(alias = "m.beacon_info")]
144        "org.matrix.msc3672.beacon_info" => super::beacon_info,
145        #[cfg(feature = "unstable-msc3401")]
146        #[ruma_enum(alias = "m.call.member")]
147        "org.matrix.msc3401.call.member" => super::call::member,
148        #[cfg(feature = "unstable-msc4171")]
149        #[ruma_enum(alias = "m.member_hints")]
150        "io.element.functional_members" => super::member_hints,
151    }
152
153    /// Any to-device event.
154    enum ToDevice {
155        "m.dummy" => super::dummy,
156        "m.room_key" => super::room_key,
157        "m.room_key_request" => super::room_key_request,
158        "m.forwarded_room_key" => super::forwarded_room_key,
159        "m.key.verification.request" => super::key::verification::request,
160        "m.key.verification.ready" => super::key::verification::ready,
161        "m.key.verification.start" => super::key::verification::start,
162        "m.key.verification.cancel" => super::key::verification::cancel,
163        "m.key.verification.accept" => super::key::verification::accept,
164        "m.key.verification.key" => super::key::verification::key,
165        "m.key.verification.mac" => super::key::verification::mac,
166        "m.key.verification.done" => super::key::verification::done,
167        "m.room.encrypted" => super::room::encrypted,
168        "m.secret.request"=> super::secret::request,
169        "m.secret.send" => super::secret::send,
170    }
171}
172
173macro_rules! timeline_event_accessors {
174    (
175        $(
176            #[doc = $docs:literal]
177            pub fn $field:ident(&self) -> $ty:ty;
178        )*
179    ) => {
180        $(
181            #[doc = $docs]
182            pub fn $field(&self) -> $ty {
183                match self {
184                    Self::MessageLike(ev) => ev.$field(),
185                    Self::State(ev) => ev.$field(),
186                }
187            }
188        )*
189    };
190}
191
192/// Any room event.
193#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
194#[derive(Clone, Debug, EventEnumFromEvent)]
195pub enum AnyTimelineEvent {
196    /// Any message-like event.
197    MessageLike(AnyMessageLikeEvent),
198
199    /// Any state event.
200    State(AnyStateEvent),
201}
202
203impl AnyTimelineEvent {
204    timeline_event_accessors! {
205        /// Returns this event's `origin_server_ts` field.
206        pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
207
208        /// Returns this event's `room_id` field.
209        pub fn room_id(&self) -> &RoomId;
210
211        /// Returns this event's `event_id` field.
212        pub fn event_id(&self) -> &EventId;
213
214        /// Returns this event's `sender` field.
215        pub fn sender(&self) -> &UserId;
216
217        /// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
218        pub fn transaction_id(&self) -> Option<&TransactionId>;
219    }
220
221    /// Returns this event's `type`.
222    pub fn event_type(&self) -> TimelineEventType {
223        match self {
224            Self::MessageLike(e) => e.event_type().into(),
225            Self::State(e) => e.event_type().into(),
226        }
227    }
228}
229
230/// Any sync room event.
231///
232/// Sync room events are room event without a `room_id`, as returned in `/sync` responses.
233#[allow(clippy::large_enum_variant, clippy::exhaustive_enums)]
234#[derive(Clone, Debug, EventEnumFromEvent)]
235pub enum AnySyncTimelineEvent {
236    /// Any sync message-like event.
237    MessageLike(AnySyncMessageLikeEvent),
238
239    /// Any sync state event.
240    State(AnySyncStateEvent),
241}
242
243impl AnySyncTimelineEvent {
244    timeline_event_accessors! {
245        /// Returns this event's `origin_server_ts` field.
246        pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch;
247
248        /// Returns this event's `event_id` field.
249        pub fn event_id(&self) -> &EventId;
250
251        /// Returns this event's `sender` field.
252        pub fn sender(&self) -> &UserId;
253
254        /// Returns this event's `transaction_id` from inside `unsigned`, if there is one.
255        pub fn transaction_id(&self) -> Option<&TransactionId>;
256    }
257
258    /// Returns this event's `type`.
259    pub fn event_type(&self) -> TimelineEventType {
260        match self {
261            Self::MessageLike(e) => e.event_type().into(),
262            Self::State(e) => e.event_type().into(),
263        }
264    }
265
266    /// Converts `self` to an `AnyTimelineEvent` by adding the given a room ID.
267    pub fn into_full_event(self, room_id: OwnedRoomId) -> AnyTimelineEvent {
268        match self {
269            Self::MessageLike(ev) => AnyTimelineEvent::MessageLike(ev.into_full_event(room_id)),
270            Self::State(ev) => AnyTimelineEvent::State(ev.into_full_event(room_id)),
271        }
272    }
273}
274
275impl From<AnyTimelineEvent> for AnySyncTimelineEvent {
276    fn from(ev: AnyTimelineEvent) -> Self {
277        match ev {
278            AnyTimelineEvent::MessageLike(ev) => Self::MessageLike(ev.into()),
279            AnyTimelineEvent::State(ev) => Self::State(ev.into()),
280        }
281    }
282}
283
284#[derive(Deserialize)]
285#[allow(clippy::exhaustive_structs)]
286struct EventDeHelper {
287    state_key: Option<de::IgnoredAny>,
288}
289
290impl<'de> Deserialize<'de> for AnyTimelineEvent {
291    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
292    where
293        D: de::Deserializer<'de>,
294    {
295        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
296        let EventDeHelper { state_key } = from_raw_json_value(&json)?;
297
298        if state_key.is_some() {
299            Ok(AnyTimelineEvent::State(from_raw_json_value(&json)?))
300        } else {
301            Ok(AnyTimelineEvent::MessageLike(from_raw_json_value(&json)?))
302        }
303    }
304}
305
306impl<'de> Deserialize<'de> for AnySyncTimelineEvent {
307    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
308    where
309        D: de::Deserializer<'de>,
310    {
311        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
312        let EventDeHelper { state_key } = from_raw_json_value(&json)?;
313
314        if state_key.is_some() {
315            Ok(AnySyncTimelineEvent::State(from_raw_json_value(&json)?))
316        } else {
317            Ok(AnySyncTimelineEvent::MessageLike(from_raw_json_value(&json)?))
318        }
319    }
320}
321
322impl AnyMessageLikeEventContent {
323    /// Get a copy of the event's `m.relates_to` field, if any.
324    ///
325    /// This is a helper function intended for encryption. There should not be a reason to access
326    /// `m.relates_to` without first destructuring an `AnyMessageLikeEventContent` otherwise.
327    pub fn relation(&self) -> Option<encrypted::Relation> {
328        #[cfg(feature = "unstable-msc3489")]
329        use super::beacon::BeaconEventContent;
330        use super::key::verification::{
331            accept::KeyVerificationAcceptEventContent, cancel::KeyVerificationCancelEventContent,
332            done::KeyVerificationDoneEventContent, key::KeyVerificationKeyEventContent,
333            mac::KeyVerificationMacEventContent, ready::KeyVerificationReadyEventContent,
334            start::KeyVerificationStartEventContent,
335        };
336        #[cfg(feature = "unstable-msc3381")]
337        use super::poll::{
338            end::PollEndEventContent, response::PollResponseEventContent,
339            unstable_end::UnstablePollEndEventContent,
340            unstable_response::UnstablePollResponseEventContent,
341        };
342
343        match self {
344            #[rustfmt::skip]
345            Self::KeyVerificationReady(KeyVerificationReadyEventContent { relates_to, .. })
346            | Self::KeyVerificationStart(KeyVerificationStartEventContent { relates_to, .. })
347            | Self::KeyVerificationCancel(KeyVerificationCancelEventContent { relates_to, .. })
348            | Self::KeyVerificationAccept(KeyVerificationAcceptEventContent { relates_to, .. })
349            | Self::KeyVerificationKey(KeyVerificationKeyEventContent { relates_to, .. })
350            | Self::KeyVerificationMac(KeyVerificationMacEventContent { relates_to, .. })
351            | Self::KeyVerificationDone(KeyVerificationDoneEventContent { relates_to, .. }) => {
352                Some(encrypted::Relation::Reference(relates_to.clone()))
353            },
354            Self::Reaction(ev) => Some(encrypted::Relation::Annotation(ev.relates_to.clone())),
355            Self::RoomEncrypted(ev) => ev.relates_to.clone(),
356            Self::RoomMessage(ev) => ev.relates_to.clone().map(Into::into),
357            #[cfg(feature = "unstable-msc1767")]
358            Self::Message(ev) => ev.relates_to.clone().map(Into::into),
359            #[cfg(feature = "unstable-msc3954")]
360            Self::Emote(ev) => ev.relates_to.clone().map(Into::into),
361            #[cfg(feature = "unstable-msc3956")]
362            Self::Encrypted(ev) => ev.relates_to.clone(),
363            #[cfg(feature = "unstable-msc3245")]
364            Self::Voice(ev) => ev.relates_to.clone().map(Into::into),
365            #[cfg(feature = "unstable-msc3927")]
366            Self::Audio(ev) => ev.relates_to.clone().map(Into::into),
367            #[cfg(feature = "unstable-msc3488")]
368            Self::Location(ev) => ev.relates_to.clone().map(Into::into),
369            #[cfg(feature = "unstable-msc3551")]
370            Self::File(ev) => ev.relates_to.clone().map(Into::into),
371            #[cfg(feature = "unstable-msc3552")]
372            Self::Image(ev) => ev.relates_to.clone().map(Into::into),
373            #[cfg(feature = "unstable-msc3553")]
374            Self::Video(ev) => ev.relates_to.clone().map(Into::into),
375            #[cfg(feature = "unstable-msc3381")]
376            Self::PollResponse(PollResponseEventContent { relates_to, .. })
377            | Self::UnstablePollResponse(UnstablePollResponseEventContent { relates_to, .. })
378            | Self::PollEnd(PollEndEventContent { relates_to, .. })
379            | Self::UnstablePollEnd(UnstablePollEndEventContent { relates_to, .. }) => {
380                Some(encrypted::Relation::Reference(relates_to.clone()))
381            }
382            #[cfg(feature = "unstable-msc3489")]
383            Self::Beacon(BeaconEventContent { relates_to, .. }) => {
384                Some(encrypted::Relation::Reference(relates_to.clone()))
385            }
386            #[cfg(feature = "unstable-msc3381")]
387            Self::PollStart(_) | Self::UnstablePollStart(_) => None,
388            #[cfg(feature = "unstable-msc4075")]
389            Self::CallNotify(_) => None,
390            Self::CallSdpStreamMetadataChanged(_)
391            | Self::CallNegotiate(_)
392            | Self::CallReject(_)
393            | Self::CallSelectAnswer(_)
394            | Self::CallAnswer(_)
395            | Self::CallInvite(_)
396            | Self::CallHangup(_)
397            | Self::CallCandidates(_)
398            | Self::RoomRedaction(_)
399            | Self::Sticker(_)
400            | Self::_Custom { .. } => None,
401        }
402    }
403}