ruma_events/
kinds.rs

1#![allow(clippy::exhaustive_structs)]
2
3use as_variant::as_variant;
4use ruma_common::{
5    encryption::DeviceKeys,
6    room_version_rules::RedactionRules,
7    serde::{from_raw_json_value, Raw},
8    EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, UserId,
9};
10use ruma_macros::Event;
11use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize};
12use serde_json::value::RawValue as RawJsonValue;
13
14use super::{
15    AnyInitialStateEvent, EmptyStateKey, EphemeralRoomEventContent, EventContentFromType,
16    GlobalAccountDataEventContent, MessageLikeEventContent, MessageLikeEventType,
17    MessageLikeUnsigned, PossiblyRedactedStateEventContent, RedactContent,
18    RedactedMessageLikeEventContent, RedactedStateEventContent, RedactedUnsigned,
19    RedactionDeHelper, RoomAccountDataEventContent, StateEventType, StaticStateEventContent,
20    ToDeviceEventContent,
21};
22
23/// A global account data event.
24#[derive(Clone, Debug, Event)]
25pub struct GlobalAccountDataEvent<C: GlobalAccountDataEventContent> {
26    /// Data specific to the event type.
27    pub content: C,
28}
29
30impl<C: GlobalAccountDataEventContent> Serialize for GlobalAccountDataEvent<C> {
31    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
32    where
33        S: serde::Serializer,
34    {
35        let mut state = serializer.serialize_struct("GlobalAccountDataEvent", 2)?;
36        state.serialize_field("type", &self.content.event_type())?;
37        state.serialize_field("content", &self.content)?;
38        state.end()
39    }
40}
41
42/// A room account data event.
43#[derive(Clone, Debug, Event)]
44pub struct RoomAccountDataEvent<C: RoomAccountDataEventContent> {
45    /// Data specific to the event type.
46    pub content: C,
47}
48
49impl<C: RoomAccountDataEventContent> Serialize for RoomAccountDataEvent<C> {
50    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
51    where
52        S: serde::Serializer,
53    {
54        let mut state = serializer.serialize_struct("RoomAccountDataEvent", 2)?;
55        state.serialize_field("type", &self.content.event_type())?;
56        state.serialize_field("content", &self.content)?;
57        state.end()
58    }
59}
60
61/// An ephemeral room event.
62#[derive(Clone, Debug, Event)]
63pub struct EphemeralRoomEvent<C: EphemeralRoomEventContent> {
64    /// Data specific to the event type.
65    pub content: C,
66
67    /// The ID of the room associated with this event.
68    pub room_id: OwnedRoomId,
69}
70
71impl<C: EphemeralRoomEventContent> Serialize for EphemeralRoomEvent<C> {
72    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
73    where
74        S: serde::Serializer,
75    {
76        let mut state = serializer.serialize_struct("EphemeralRoomEvent", 2)?;
77        state.serialize_field("type", &self.content.event_type())?;
78        state.serialize_field("content", &self.content)?;
79        state.serialize_field("room_id", &self.room_id)?;
80        state.end()
81    }
82}
83
84/// An ephemeral room event without a `room_id`.
85#[derive(Clone, Debug, Event)]
86pub struct SyncEphemeralRoomEvent<C: EphemeralRoomEventContent> {
87    /// Data specific to the event type.
88    pub content: C,
89}
90
91impl<C: EphemeralRoomEventContent> Serialize for SyncEphemeralRoomEvent<C> {
92    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
93    where
94        S: serde::Serializer,
95    {
96        let mut state = serializer.serialize_struct("SyncEphemeralRoomEvent", 2)?;
97        state.serialize_field("type", &self.content.event_type())?;
98        state.serialize_field("content", &self.content)?;
99        state.end()
100    }
101}
102
103/// An unredacted message-like event.
104///
105/// `OriginalMessageLikeEvent` implements the comparison traits using only the `event_id` field, a
106/// sorted list would be sorted lexicographically based on the event's `EventId`.
107#[derive(Clone, Debug, Event)]
108pub struct OriginalMessageLikeEvent<C: MessageLikeEventContent> {
109    /// Data specific to the event type.
110    pub content: C,
111
112    /// The globally unique event identifier for the user who sent the event.
113    pub event_id: OwnedEventId,
114
115    /// The fully-qualified ID of the user who sent this event.
116    pub sender: OwnedUserId,
117
118    /// Timestamp in milliseconds on originating homeserver when this event was sent.
119    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
120
121    /// The ID of the room associated with this event.
122    pub room_id: OwnedRoomId,
123
124    /// Additional key-value pairs not signed by the homeserver.
125    pub unsigned: MessageLikeUnsigned<C>,
126}
127
128/// An unredacted message-like event without a `room_id`.
129///
130/// `OriginalSyncMessageLikeEvent` implements the comparison traits using only the `event_id` field,
131/// a sorted list would be sorted lexicographically based on the event's `EventId`.
132#[derive(Clone, Debug, Event)]
133pub struct OriginalSyncMessageLikeEvent<C: MessageLikeEventContent> {
134    /// Data specific to the event type.
135    pub content: C,
136
137    /// The globally unique event identifier for the user who sent the event.
138    pub event_id: OwnedEventId,
139
140    /// The fully-qualified ID of the user who sent this event.
141    pub sender: OwnedUserId,
142
143    /// Timestamp in milliseconds on originating homeserver when this event was sent.
144    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
145
146    /// Additional key-value pairs not signed by the homeserver.
147    pub unsigned: MessageLikeUnsigned<C>,
148}
149
150impl<C: MessageLikeEventContent + RedactContent> OriginalSyncMessageLikeEvent<C>
151where
152    C::Redacted: RedactedMessageLikeEventContent,
153{
154    pub(crate) fn into_maybe_redacted(self) -> SyncMessageLikeEvent<C> {
155        SyncMessageLikeEvent::Original(self)
156    }
157}
158
159/// A redacted message-like event.
160///
161/// `RedactedMessageLikeEvent` implements the comparison traits using only the `event_id` field, a
162/// sorted list would be sorted lexicographically based on the event's `EventId`.
163#[derive(Clone, Debug, Event)]
164pub struct RedactedMessageLikeEvent<C: RedactedMessageLikeEventContent> {
165    /// Data specific to the event type.
166    pub content: C,
167
168    /// The globally unique event identifier for the user who sent the event.
169    pub event_id: OwnedEventId,
170
171    /// The fully-qualified ID of the user who sent this event.
172    pub sender: OwnedUserId,
173
174    /// Timestamp in milliseconds on originating homeserver when this event was sent.
175    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
176
177    /// The ID of the room associated with this event.
178    pub room_id: OwnedRoomId,
179
180    /// Additional key-value pairs not signed by the homeserver.
181    pub unsigned: RedactedUnsigned,
182}
183
184/// A redacted message-like event without a `room_id`.
185///
186/// `RedactedSyncMessageLikeEvent` implements the comparison traits using only the `event_id` field,
187/// a sorted list would be sorted lexicographically based on the event's `EventId`.
188#[derive(Clone, Debug, Event)]
189pub struct RedactedSyncMessageLikeEvent<C: RedactedMessageLikeEventContent> {
190    /// Data specific to the event type.
191    pub content: C,
192
193    /// The globally unique event identifier for the user who sent the event.
194    pub event_id: OwnedEventId,
195
196    /// The fully-qualified ID of the user who sent this event.
197    pub sender: OwnedUserId,
198
199    /// Timestamp in milliseconds on originating homeserver when this event was sent.
200    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
201
202    /// Additional key-value pairs not signed by the homeserver.
203    pub unsigned: RedactedUnsigned,
204}
205
206/// A possibly-redacted message-like event.
207///
208/// `MessageLikeEvent` implements the comparison traits using only the `event_id` field, a sorted
209/// list would be sorted lexicographically based on the event's `EventId`.
210#[allow(clippy::exhaustive_enums)]
211#[derive(Clone, Debug)]
212pub enum MessageLikeEvent<C: MessageLikeEventContent + RedactContent>
213where
214    C::Redacted: RedactedMessageLikeEventContent,
215{
216    /// Original, unredacted form of the event.
217    Original(OriginalMessageLikeEvent<C>),
218
219    /// Redacted form of the event with minimal fields.
220    Redacted(RedactedMessageLikeEvent<C::Redacted>),
221}
222
223/// A possibly-redacted message-like event without a `room_id`.
224///
225/// `SyncMessageLikeEvent` implements the comparison traits using only the `event_id` field, a
226/// sorted list would be sorted lexicographically based on the event's `EventId`.
227#[allow(clippy::exhaustive_enums)]
228#[derive(Clone, Debug)]
229pub enum SyncMessageLikeEvent<C: MessageLikeEventContent + RedactContent>
230where
231    C::Redacted: RedactedMessageLikeEventContent,
232{
233    /// Original, unredacted form of the event.
234    Original(OriginalSyncMessageLikeEvent<C>),
235
236    /// Redacted form of the event with minimal fields.
237    Redacted(RedactedSyncMessageLikeEvent<C::Redacted>),
238}
239
240/// An unredacted state event.
241///
242/// `OriginalStateEvent` implements the comparison traits using only the `event_id` field, a sorted
243/// list would be sorted lexicographically based on the event's `EventId`.
244#[derive(Clone, Debug, Event)]
245pub struct OriginalStateEvent<C: StaticStateEventContent> {
246    /// Data specific to the event type.
247    pub content: C,
248
249    /// The globally unique event identifier for the user who sent the event.
250    pub event_id: OwnedEventId,
251
252    /// The fully-qualified ID of the user who sent this event.
253    pub sender: OwnedUserId,
254
255    /// Timestamp in milliseconds on originating homeserver when this event was sent.
256    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
257
258    /// The ID of the room associated with this event.
259    pub room_id: OwnedRoomId,
260
261    /// A unique key which defines the overwriting semantics for this piece of room state.
262    ///
263    /// This is often an empty string, but some events send a `UserId` to show which user the event
264    /// affects.
265    pub state_key: C::StateKey,
266
267    /// Additional key-value pairs not signed by the homeserver.
268    pub unsigned: C::Unsigned,
269}
270
271/// An unredacted state event without a `room_id`.
272///
273/// `OriginalSyncStateEvent` implements the comparison traits using only the `event_id` field, a
274/// sorted list would be sorted lexicographically based on the event's `EventId`.
275#[derive(Clone, Debug, Event)]
276pub struct OriginalSyncStateEvent<C: StaticStateEventContent> {
277    /// Data specific to the event type.
278    pub content: C,
279
280    /// The globally unique event identifier for the user who sent the event.
281    pub event_id: OwnedEventId,
282
283    /// The fully-qualified ID of the user who sent this event.
284    pub sender: OwnedUserId,
285
286    /// Timestamp in milliseconds on originating homeserver when this event was sent.
287    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
288
289    /// A unique key which defines the overwriting semantics for this piece of room state.
290    ///
291    /// This is often an empty string, but some events send a `UserId` to show which user the event
292    /// affects.
293    pub state_key: C::StateKey,
294
295    /// Additional key-value pairs not signed by the homeserver.
296    pub unsigned: C::Unsigned,
297}
298
299/// A stripped-down state event, used for previews of rooms the user has been invited to.
300#[derive(Clone, Debug, Event)]
301pub struct StrippedStateEvent<C: PossiblyRedactedStateEventContent> {
302    /// Data specific to the event type.
303    pub content: C,
304
305    /// The fully-qualified ID of the user who sent this event.
306    pub sender: OwnedUserId,
307
308    /// A unique key which defines the overwriting semantics for this piece of room state.
309    ///
310    /// This is often an empty string, but some events send a `UserId` to show which user the event
311    /// affects.
312    pub state_key: C::StateKey,
313}
314
315/// A minimal state event, used for creating a new room.
316#[derive(Clone, Debug, Event)]
317pub struct InitialStateEvent<C: StaticStateEventContent> {
318    /// Data specific to the event type.
319    pub content: C,
320
321    /// A unique key which defines the overwriting semantics for this piece of room state.
322    ///
323    /// This is often an empty string, but some events send a `UserId` to show which user the event
324    /// affects.
325    ///
326    /// Defaults to the empty string.
327    pub state_key: C::StateKey,
328}
329
330impl<C: StaticStateEventContent> InitialStateEvent<C> {
331    /// Create a new `InitialStateEvent` for an event type with an empty state key.
332    ///
333    /// For cases where the state key is not empty, use a struct literal to create the event.
334    pub fn new(content: C) -> Self
335    where
336        C: StaticStateEventContent<StateKey = EmptyStateKey>,
337    {
338        Self { content, state_key: EmptyStateKey }
339    }
340
341    /// Shorthand for `Raw::new(self).unwrap()`.
342    ///
343    /// Since none of the content types in Ruma ever return an error in serialization, this will
344    /// never panic with `C` being a type from Ruma. However, if you use a custom content type
345    /// with a `Serialize` implementation that can error (for example because it contains an
346    /// `enum` with one or more variants that use the `#[serde(skip)]` attribute), this method
347    /// can panic.
348    pub fn to_raw(&self) -> Raw<Self> {
349        Raw::new(self).unwrap()
350    }
351
352    /// Shorthand for `self.to_raw().cast::<AnyInitialStateEvent>()`.
353    ///
354    /// Since none of the content types in Ruma ever return an error in serialization, this will
355    /// never panic with `C` being a type from Ruma. However, if you use a custom content type
356    /// with a `Serialize` implementation that can error (for example because it contains an
357    /// `enum` with one or more variants that use the `#[serde(skip)]` attribute), this method
358    /// can panic.
359    pub fn to_raw_any(&self) -> Raw<AnyInitialStateEvent> {
360        self.to_raw().cast()
361    }
362}
363
364impl<C> Default for InitialStateEvent<C>
365where
366    C: StaticStateEventContent<StateKey = EmptyStateKey> + Default,
367{
368    fn default() -> Self {
369        Self { content: Default::default(), state_key: EmptyStateKey }
370    }
371}
372
373impl<C: StaticStateEventContent> Serialize for InitialStateEvent<C> {
374    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
375    where
376        S: serde::Serializer,
377    {
378        let mut state = serializer.serialize_struct("InitialStateEvent", 3)?;
379        state.serialize_field("type", &self.content.event_type())?;
380        state.serialize_field("content", &self.content)?;
381        state.serialize_field("state_key", &self.state_key)?;
382        state.end()
383    }
384}
385
386/// A redacted state event.
387///
388/// `RedactedStateEvent` implements the comparison traits using only the `event_id` field, a sorted
389/// list would be sorted lexicographically based on the event's `EventId`.
390#[derive(Clone, Debug, Event)]
391pub struct RedactedStateEvent<C: RedactedStateEventContent> {
392    /// Data specific to the event type.
393    pub content: C,
394
395    /// The globally unique event identifier for the user who sent the event.
396    pub event_id: OwnedEventId,
397
398    /// The fully-qualified ID of the user who sent this event.
399    pub sender: OwnedUserId,
400
401    /// Timestamp in milliseconds on originating homeserver when this event was sent.
402    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
403
404    /// The ID of the room associated with this event.
405    pub room_id: OwnedRoomId,
406
407    /// A unique key which defines the overwriting semantics for this piece of room state.
408    ///
409    /// This is often an empty string, but some events send a `UserId` to show which user the event
410    /// affects.
411    pub state_key: C::StateKey,
412
413    /// Additional key-value pairs not signed by the homeserver.
414    pub unsigned: RedactedUnsigned,
415}
416
417/// A redacted state event without a `room_id`.
418///
419/// `RedactedSyncStateEvent` implements the comparison traits using only the `event_id` field, a
420/// sorted list would be sorted lexicographically based on the event's `EventId`.
421#[derive(Clone, Debug, Event)]
422pub struct RedactedSyncStateEvent<C: RedactedStateEventContent> {
423    /// Data specific to the event type.
424    pub content: C,
425
426    /// The globally unique event identifier for the user who sent the event.
427    pub event_id: OwnedEventId,
428
429    /// The fully-qualified ID of the user who sent this event.
430    pub sender: OwnedUserId,
431
432    /// Timestamp in milliseconds on originating homeserver when this event was sent.
433    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
434
435    /// A unique key which defines the overwriting semantics for this piece of room state.
436    ///
437    /// This is often an empty string, but some events send a `UserId` to show which user the event
438    /// affects.
439    pub state_key: C::StateKey,
440
441    /// Additional key-value pairs not signed by the homeserver.
442    pub unsigned: RedactedUnsigned,
443}
444
445/// A possibly-redacted state event.
446///
447/// `StateEvent` implements the comparison traits using only the `event_id` field, a sorted list
448/// would be sorted lexicographically based on the event's `EventId`.
449#[allow(clippy::exhaustive_enums)]
450#[derive(Clone, Debug)]
451pub enum StateEvent<C: StaticStateEventContent + RedactContent>
452where
453    C::Redacted: RedactedStateEventContent,
454{
455    /// Original, unredacted form of the event.
456    Original(OriginalStateEvent<C>),
457
458    /// Redacted form of the event with minimal fields.
459    Redacted(RedactedStateEvent<C::Redacted>),
460}
461
462/// A possibly-redacted state event without a `room_id`.
463///
464/// `SyncStateEvent` implements the comparison traits using only the `event_id` field, a sorted list
465/// would be sorted lexicographically based on the event's `EventId`.
466#[allow(clippy::exhaustive_enums)]
467#[derive(Clone, Debug)]
468pub enum SyncStateEvent<C: StaticStateEventContent + RedactContent>
469where
470    C::Redacted: RedactedStateEventContent,
471{
472    /// Original, unredacted form of the event.
473    Original(OriginalSyncStateEvent<C>),
474
475    /// Redacted form of the event with minimal fields.
476    Redacted(RedactedSyncStateEvent<C::Redacted>),
477}
478
479/// An event sent using send-to-device messaging.
480#[derive(Clone, Debug, Event)]
481pub struct ToDeviceEvent<C: ToDeviceEventContent> {
482    /// Data specific to the event type.
483    pub content: C,
484
485    /// The fully-qualified ID of the user who sent this event.
486    pub sender: OwnedUserId,
487}
488
489impl<C: ToDeviceEventContent> Serialize for ToDeviceEvent<C> {
490    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
491    where
492        S: serde::Serializer,
493    {
494        let mut state = serializer.serialize_struct("ToDeviceEvent", 3)?;
495        state.serialize_field("type", &self.content.event_type())?;
496        state.serialize_field("content", &self.content)?;
497        state.serialize_field("sender", &self.sender)?;
498        state.end()
499    }
500}
501
502/// The decrypted payload of an `m.olm.v1.curve25519-aes-sha2` event.
503#[derive(Clone, Debug, Event)]
504pub struct DecryptedOlmV1Event<C: MessageLikeEventContent> {
505    /// Data specific to the event type.
506    pub content: C,
507
508    /// The fully-qualified ID of the user who sent this event.
509    pub sender: OwnedUserId,
510
511    /// The fully-qualified ID of the intended recipient this event.
512    pub recipient: OwnedUserId,
513
514    /// The recipient's ed25519 key.
515    pub recipient_keys: OlmV1Keys,
516
517    /// The sender's ed25519 key.
518    pub keys: OlmV1Keys,
519
520    /// The sender's device keys.
521    pub sender_device_keys: Option<Raw<DeviceKeys>>,
522}
523
524/// Public keys used for an `m.olm.v1.curve25519-aes-sha2` event.
525#[derive(Clone, Debug, Deserialize, Serialize)]
526pub struct OlmV1Keys {
527    /// An ed25519 key.
528    pub ed25519: String,
529}
530
531/// The decrypted payload of an `m.megolm.v1.aes-sha2` event.
532#[derive(Clone, Debug, Event)]
533pub struct DecryptedMegolmV1Event<C: MessageLikeEventContent> {
534    /// Data specific to the event type.
535    pub content: C,
536
537    /// The ID of the room associated with the event.
538    pub room_id: OwnedRoomId,
539}
540
541/// A possibly-redacted state event content.
542///
543/// A non-redacted content also contains the `prev_content` from the unsigned event data.
544#[allow(clippy::exhaustive_enums)]
545#[derive(Clone, Debug)]
546pub enum FullStateEventContent<C: StaticStateEventContent + RedactContent> {
547    /// Original, unredacted content of the event.
548    Original {
549        /// Current content of the room state.
550        content: C,
551
552        /// Previous content of the room state.
553        prev_content: Option<C::PossiblyRedacted>,
554    },
555
556    /// Redacted content of the event.
557    Redacted(C::Redacted),
558}
559
560impl<C: StaticStateEventContent + RedactContent> FullStateEventContent<C>
561where
562    C::Redacted: RedactedStateEventContent,
563{
564    /// Get the event’s type, like `m.room.create`.
565    pub fn event_type(&self) -> StateEventType {
566        match self {
567            Self::Original { content, .. } => content.event_type(),
568            Self::Redacted(content) => content.event_type(),
569        }
570    }
571
572    /// Transform `self` into a redacted form (removing most or all fields) according to the spec.
573    ///
574    /// If `self` is already [`Redacted`](Self::Redacted), return the inner data unmodified.
575    ///
576    /// A small number of events have room-version specific redaction behavior, so a
577    /// [`RedactionRules`] has to be specified.
578    pub fn redact(self, rules: &RedactionRules) -> C::Redacted {
579        match self {
580            FullStateEventContent::Original { content, .. } => content.redact(rules),
581            FullStateEventContent::Redacted(content) => content,
582        }
583    }
584}
585
586macro_rules! impl_possibly_redacted_event {
587    (
588        $ty:ident ( $content_trait:ident, $redacted_content_trait:ident, $event_type:ident )
589        $( where C::Redacted: $trait:ident<StateKey = C::StateKey>, )?
590        { $($extra:tt)* }
591    ) => {
592        impl<C> $ty<C>
593        where
594            C: $content_trait + RedactContent,
595            C::Redacted: $redacted_content_trait,
596            $( C::Redacted: $trait<StateKey = C::StateKey>, )?
597        {
598            /// Returns the `type` of this event.
599            pub fn event_type(&self) -> $event_type {
600                match self {
601                    Self::Original(ev) => ev.content.event_type(),
602                    Self::Redacted(ev) => ev.content.event_type(),
603                }
604            }
605
606            /// Returns this event's `event_id` field.
607            pub fn event_id(&self) -> &EventId {
608                match self {
609                    Self::Original(ev) => &ev.event_id,
610                    Self::Redacted(ev) => &ev.event_id,
611                }
612            }
613
614            /// Returns this event's `sender` field.
615            pub fn sender(&self) -> &UserId {
616                match self {
617                    Self::Original(ev) => &ev.sender,
618                    Self::Redacted(ev) => &ev.sender,
619                }
620            }
621
622            /// Returns this event's `origin_server_ts` field.
623            pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
624                match self {
625                    Self::Original(ev) => ev.origin_server_ts,
626                    Self::Redacted(ev) => ev.origin_server_ts,
627                }
628            }
629
630            // So the room_id method can be in the same impl block, in rustdoc
631            $($extra)*
632        }
633
634        impl<'de, C> Deserialize<'de> for $ty<C>
635        where
636            C: $content_trait + EventContentFromType + RedactContent,
637            C::Redacted: $redacted_content_trait + EventContentFromType,
638            $( C::Redacted: $trait<StateKey = C::StateKey>, )?
639        {
640            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
641            where
642                D: Deserializer<'de>,
643            {
644                let json = Box::<RawJsonValue>::deserialize(deserializer)?;
645                let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;
646
647                if unsigned.and_then(|u| u.redacted_because).is_some() {
648                    Ok(Self::Redacted(from_raw_json_value(&json)?))
649                } else {
650                    Ok(Self::Original(from_raw_json_value(&json)?))
651                }
652            }
653        }
654    }
655}
656
657impl_possibly_redacted_event!(
658    MessageLikeEvent(
659        MessageLikeEventContent, RedactedMessageLikeEventContent, MessageLikeEventType
660    ) {
661        /// Returns this event's `room_id` field.
662        pub fn room_id(&self) -> &RoomId {
663            match self {
664                Self::Original(ev) => &ev.room_id,
665                Self::Redacted(ev) => &ev.room_id,
666            }
667        }
668
669        /// Get the inner `OriginalMessageLikeEvent` if this is an unredacted event.
670        pub fn as_original(&self) -> Option<&OriginalMessageLikeEvent<C>> {
671            as_variant!(self, Self::Original)
672        }
673    }
674);
675
676impl_possibly_redacted_event!(
677    SyncMessageLikeEvent(
678        MessageLikeEventContent, RedactedMessageLikeEventContent, MessageLikeEventType
679    ) {
680        /// Get the inner `OriginalSyncMessageLikeEvent` if this is an unredacted event.
681        pub fn as_original(&self) -> Option<&OriginalSyncMessageLikeEvent<C>> {
682            as_variant!(self, Self::Original)
683        }
684
685        /// Convert this sync event into a full event (one with a `room_id` field).
686        pub fn into_full_event(self, room_id: OwnedRoomId) -> MessageLikeEvent<C> {
687            match self {
688                Self::Original(ev) => MessageLikeEvent::Original(ev.into_full_event(room_id)),
689                Self::Redacted(ev) => MessageLikeEvent::Redacted(ev.into_full_event(room_id)),
690            }
691        }
692    }
693);
694
695impl_possibly_redacted_event!(
696    StateEvent(StaticStateEventContent, RedactedStateEventContent, StateEventType)
697    where
698        C::Redacted: RedactedStateEventContent<StateKey = C::StateKey>,
699    {
700        /// Returns this event's `room_id` field.
701        pub fn room_id(&self) -> &RoomId {
702            match self {
703                Self::Original(ev) => &ev.room_id,
704                Self::Redacted(ev) => &ev.room_id,
705            }
706        }
707
708        /// Returns this event's `state_key` field.
709        pub fn state_key(&self) -> &C::StateKey {
710            match self {
711                Self::Original(ev) => &ev.state_key,
712                Self::Redacted(ev) => &ev.state_key,
713            }
714        }
715
716        /// Get the inner `OriginalStateEvent` if this is an unredacted event.
717        pub fn as_original(&self) -> Option<&OriginalStateEvent<C>> {
718            as_variant!(self, Self::Original)
719        }
720    }
721);
722
723impl_possibly_redacted_event!(
724    SyncStateEvent(StaticStateEventContent, RedactedStateEventContent, StateEventType)
725    where
726        C::Redacted: RedactedStateEventContent<StateKey = C::StateKey>,
727    {
728        /// Returns this event's `state_key` field.
729        pub fn state_key(&self) -> &C::StateKey {
730            match self {
731                Self::Original(ev) => &ev.state_key,
732                Self::Redacted(ev) => &ev.state_key,
733            }
734        }
735
736        /// Get the inner `OriginalSyncStateEvent` if this is an unredacted event.
737        pub fn as_original(&self) -> Option<&OriginalSyncStateEvent<C>> {
738            as_variant!(self, Self::Original)
739        }
740
741        /// Convert this sync event into a full event (one with a `room_id` field).
742        pub fn into_full_event(self, room_id: OwnedRoomId) -> StateEvent<C> {
743            match self {
744                Self::Original(ev) => StateEvent::Original(ev.into_full_event(room_id)),
745                Self::Redacted(ev) => StateEvent::Redacted(ev.into_full_event(room_id)),
746            }
747        }
748    }
749);
750
751macro_rules! impl_sync_from_full {
752    ($ty:ident, $full:ident, $content_trait:ident, $redacted_content_trait: ident) => {
753        impl<C> From<$full<C>> for $ty<C>
754        where
755            C: $content_trait + RedactContent,
756            C::Redacted: $redacted_content_trait,
757        {
758            fn from(full: $full<C>) -> Self {
759                match full {
760                    $full::Original(ev) => Self::Original(ev.into()),
761                    $full::Redacted(ev) => Self::Redacted(ev.into()),
762                }
763            }
764        }
765    };
766}
767
768impl_sync_from_full!(
769    SyncMessageLikeEvent,
770    MessageLikeEvent,
771    MessageLikeEventContent,
772    RedactedMessageLikeEventContent
773);
774impl_sync_from_full!(
775    SyncStateEvent,
776    StateEvent,
777    StaticStateEventContent,
778    RedactedStateEventContent
779);