Skip to main content

ruma_events/
kinds.rs

1use as_variant::as_variant;
2use ruma_common::{
3    EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, UserId,
4    encryption::DeviceKeys,
5    room_version_rules::RedactionRules,
6    serde::{JsonCastable, JsonObject, Raw, from_raw_json_value},
7};
8use ruma_macros::Event;
9use serde::{Deserialize, Deserializer, Serialize, ser::SerializeStruct};
10use serde_json::value::RawValue as RawJsonValue;
11
12use super::{
13    AnyInitialStateEvent, EmptyStateKey, EphemeralRoomEventContent, EventContentFromType,
14    GlobalAccountDataEventContent, MessageLikeEventContent, MessageLikeEventType,
15    MessageLikeUnsigned, PossiblyRedactedStateEventContent, RedactContent,
16    RedactedMessageLikeEventContent, RedactedStateEventContent, RedactedUnsigned,
17    RedactionDeHelper, RoomAccountDataEventContent, StateEventType, StaticStateEventContent,
18    ToDeviceEventContent,
19};
20
21/// A global account data event.
22#[derive(Clone, Debug, Event)]
23#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
24pub struct GlobalAccountDataEvent<C: GlobalAccountDataEventContent> {
25    /// Data specific to the event type.
26    pub content: C,
27}
28
29impl<C: GlobalAccountDataEventContent> GlobalAccountDataEvent<C> {
30    /// Construct a new `GlobalAccountDataEvent` with the given content.
31    pub fn new(content: C) -> Self {
32        Self { content }
33    }
34}
35
36impl<C: GlobalAccountDataEventContent> Serialize for GlobalAccountDataEvent<C> {
37    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
38    where
39        S: serde::Serializer,
40    {
41        let mut state = serializer.serialize_struct("GlobalAccountDataEvent", 2)?;
42        state.serialize_field("type", &self.content.event_type())?;
43        state.serialize_field("content", &self.content)?;
44        state.end()
45    }
46}
47
48impl<C: GlobalAccountDataEventContent> JsonCastable<JsonObject> for GlobalAccountDataEvent<C> {}
49
50/// A room account data event.
51#[derive(Clone, Debug, Event)]
52#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
53pub struct RoomAccountDataEvent<C: RoomAccountDataEventContent> {
54    /// Data specific to the event type.
55    pub content: C,
56}
57
58impl<C: RoomAccountDataEventContent> RoomAccountDataEvent<C> {
59    /// Construct a new `RoomAccountDataEvent` with the given content.
60    pub fn new(content: C) -> Self {
61        Self { content }
62    }
63}
64
65impl<C: RoomAccountDataEventContent> Serialize for RoomAccountDataEvent<C> {
66    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
67    where
68        S: serde::Serializer,
69    {
70        let mut state = serializer.serialize_struct("RoomAccountDataEvent", 2)?;
71        state.serialize_field("type", &self.content.event_type())?;
72        state.serialize_field("content", &self.content)?;
73        state.end()
74    }
75}
76
77impl<C: RoomAccountDataEventContent> JsonCastable<JsonObject> for RoomAccountDataEvent<C> {}
78
79/// An ephemeral room event.
80#[derive(Clone, Debug, Event)]
81#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
82pub struct EphemeralRoomEvent<C: EphemeralRoomEventContent> {
83    /// Data specific to the event type.
84    pub content: C,
85
86    /// The ID of the room associated with this event.
87    pub room_id: OwnedRoomId,
88}
89
90impl<C: EphemeralRoomEventContent> EphemeralRoomEvent<C> {
91    /// Construct a new `EphemeralRoomEvent` with the given content and room ID.
92    pub fn new(room_id: OwnedRoomId, content: C) -> Self {
93        Self { content, room_id }
94    }
95}
96
97impl<C: EphemeralRoomEventContent> Serialize for EphemeralRoomEvent<C> {
98    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
99    where
100        S: serde::Serializer,
101    {
102        let mut state = serializer.serialize_struct("EphemeralRoomEvent", 2)?;
103        state.serialize_field("type", &self.content.event_type())?;
104        state.serialize_field("content", &self.content)?;
105        state.serialize_field("room_id", &self.room_id)?;
106        state.end()
107    }
108}
109
110impl<C: EphemeralRoomEventContent> JsonCastable<SyncEphemeralRoomEvent<C>>
111    for EphemeralRoomEvent<C>
112{
113}
114
115impl<C: EphemeralRoomEventContent> JsonCastable<JsonObject> for EphemeralRoomEvent<C> {}
116
117/// An ephemeral room event without a `room_id`.
118#[derive(Clone, Debug, Event)]
119#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
120pub struct SyncEphemeralRoomEvent<C: EphemeralRoomEventContent> {
121    /// Data specific to the event type.
122    pub content: C,
123}
124
125impl<C: EphemeralRoomEventContent> SyncEphemeralRoomEvent<C> {
126    /// Construct a new `SyncEphemeralRoomEvent` with the given content and room ID.
127    pub fn new(content: C) -> Self {
128        Self { content }
129    }
130}
131
132impl<C: EphemeralRoomEventContent> Serialize for SyncEphemeralRoomEvent<C> {
133    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
134    where
135        S: serde::Serializer,
136    {
137        let mut state = serializer.serialize_struct("SyncEphemeralRoomEvent", 2)?;
138        state.serialize_field("type", &self.content.event_type())?;
139        state.serialize_field("content", &self.content)?;
140        state.end()
141    }
142}
143
144impl<C: EphemeralRoomEventContent> JsonCastable<JsonObject> for SyncEphemeralRoomEvent<C> {}
145
146/// An unredacted message-like event.
147///
148/// `OriginalMessageLikeEvent` implements the comparison traits using only the `event_id` field, a
149/// sorted list would be sorted lexicographically based on the event's `EventId`.
150#[derive(Clone, Debug, Event)]
151#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
152pub struct OriginalMessageLikeEvent<C: MessageLikeEventContent> {
153    /// Data specific to the event type.
154    pub content: C,
155
156    /// The globally unique identifier for the event.
157    pub event_id: OwnedEventId,
158
159    /// The fully-qualified ID of the user who sent this event.
160    pub sender: OwnedUserId,
161
162    /// Timestamp on the originating homeserver when this event was sent.
163    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
164
165    /// The ID of the room associated with this event.
166    pub room_id: OwnedRoomId,
167
168    /// Additional key-value pairs not signed by the homeserver.
169    pub unsigned: MessageLikeUnsigned<C>,
170}
171
172impl<C: MessageLikeEventContent> JsonCastable<OriginalSyncMessageLikeEvent<C>>
173    for OriginalMessageLikeEvent<C>
174{
175}
176
177impl<C: MessageLikeEventContent + RedactContent> JsonCastable<MessageLikeEvent<C>>
178    for OriginalMessageLikeEvent<C>
179where
180    C::Redacted: RedactedMessageLikeEventContent,
181{
182}
183
184impl<C: MessageLikeEventContent + RedactContent> JsonCastable<SyncMessageLikeEvent<C>>
185    for OriginalMessageLikeEvent<C>
186where
187    C::Redacted: RedactedMessageLikeEventContent,
188{
189}
190
191impl<C: MessageLikeEventContent> JsonCastable<JsonObject> for OriginalMessageLikeEvent<C> {}
192
193/// An unredacted message-like event without a `room_id`.
194///
195/// `OriginalSyncMessageLikeEvent` implements the comparison traits using only the `event_id` field,
196/// a sorted list would be sorted lexicographically based on the event's `EventId`.
197#[derive(Clone, Debug, Event)]
198#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
199pub struct OriginalSyncMessageLikeEvent<C: MessageLikeEventContent> {
200    /// Data specific to the event type.
201    pub content: C,
202
203    /// The globally unique identifier for the event.
204    pub event_id: OwnedEventId,
205
206    /// The fully-qualified ID of the user who sent this event.
207    pub sender: OwnedUserId,
208
209    /// Timestamp on the originating homeserver when this event was sent.
210    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
211
212    /// Additional key-value pairs not signed by the homeserver.
213    pub unsigned: MessageLikeUnsigned<C>,
214}
215
216impl<C: MessageLikeEventContent + RedactContent> OriginalSyncMessageLikeEvent<C>
217where
218    C::Redacted: RedactedMessageLikeEventContent,
219{
220    pub(crate) fn into_maybe_redacted(self) -> SyncMessageLikeEvent<C> {
221        SyncMessageLikeEvent::Original(self)
222    }
223}
224
225impl<C: MessageLikeEventContent + RedactContent> JsonCastable<SyncMessageLikeEvent<C>>
226    for OriginalSyncMessageLikeEvent<C>
227where
228    C::Redacted: RedactedMessageLikeEventContent,
229{
230}
231
232impl<C: MessageLikeEventContent> JsonCastable<JsonObject> for OriginalSyncMessageLikeEvent<C> {}
233
234/// A redacted message-like event.
235///
236/// `RedactedMessageLikeEvent` implements the comparison traits using only the `event_id` field, a
237/// sorted list would be sorted lexicographically based on the event's `EventId`.
238#[derive(Clone, Debug, Event)]
239#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
240pub struct RedactedMessageLikeEvent<C: RedactedMessageLikeEventContent> {
241    /// Data specific to the event type.
242    pub content: C,
243
244    /// The globally unique identifier for the event.
245    pub event_id: OwnedEventId,
246
247    /// The fully-qualified ID of the user who sent this event.
248    pub sender: OwnedUserId,
249
250    /// Timestamp on the originating homeserver when this event was sent.
251    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
252
253    /// The ID of the room associated with this event.
254    pub room_id: OwnedRoomId,
255
256    /// Additional key-value pairs not signed by the homeserver.
257    pub unsigned: RedactedUnsigned,
258}
259
260impl<C: RedactedMessageLikeEventContent> JsonCastable<RedactedSyncMessageLikeEvent<C>>
261    for RedactedMessageLikeEvent<C>
262{
263}
264
265impl<C: MessageLikeEventContent + RedactContent> JsonCastable<MessageLikeEvent<C>>
266    for RedactedMessageLikeEvent<C::Redacted>
267where
268    C::Redacted: RedactedMessageLikeEventContent,
269{
270}
271
272impl<C: MessageLikeEventContent + RedactContent> JsonCastable<SyncMessageLikeEvent<C>>
273    for RedactedMessageLikeEvent<C::Redacted>
274where
275    C::Redacted: RedactedMessageLikeEventContent,
276{
277}
278
279impl<C: RedactedMessageLikeEventContent> JsonCastable<JsonObject> for RedactedMessageLikeEvent<C> {}
280
281/// A redacted message-like event without a `room_id`.
282///
283/// `RedactedSyncMessageLikeEvent` implements the comparison traits using only the `event_id` field,
284/// a sorted list would be sorted lexicographically based on the event's `EventId`.
285#[derive(Clone, Debug, Event)]
286#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
287pub struct RedactedSyncMessageLikeEvent<C: RedactedMessageLikeEventContent> {
288    /// Data specific to the event type.
289    pub content: C,
290
291    /// The globally unique identifier for the event.
292    pub event_id: OwnedEventId,
293
294    /// The fully-qualified ID of the user who sent this event.
295    pub sender: OwnedUserId,
296
297    /// Timestamp on the originating homeserver when this event was sent.
298    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
299
300    /// Additional key-value pairs not signed by the homeserver.
301    pub unsigned: RedactedUnsigned,
302}
303
304impl<C: MessageLikeEventContent + RedactContent> JsonCastable<SyncMessageLikeEvent<C>>
305    for RedactedSyncMessageLikeEvent<C::Redacted>
306where
307    C::Redacted: RedactedMessageLikeEventContent,
308{
309}
310
311impl<C: RedactedMessageLikeEventContent> JsonCastable<JsonObject>
312    for RedactedSyncMessageLikeEvent<C>
313{
314}
315
316/// A possibly-redacted message-like event.
317///
318/// `MessageLikeEvent` implements the comparison traits using only the `event_id` field, a sorted
319/// list would be sorted lexicographically based on the event's `EventId`.
320#[allow(clippy::exhaustive_enums)]
321#[derive(Clone, Debug)]
322pub enum MessageLikeEvent<C: MessageLikeEventContent + RedactContent>
323where
324    C::Redacted: RedactedMessageLikeEventContent,
325{
326    /// Original, unredacted form of the event.
327    Original(OriginalMessageLikeEvent<C>),
328
329    /// Redacted form of the event with minimal fields.
330    Redacted(RedactedMessageLikeEvent<C::Redacted>),
331}
332
333impl<C: MessageLikeEventContent + RedactContent> JsonCastable<SyncMessageLikeEvent<C>>
334    for MessageLikeEvent<C>
335where
336    C::Redacted: RedactedMessageLikeEventContent,
337{
338}
339
340impl<C: MessageLikeEventContent + RedactContent> JsonCastable<JsonObject> for MessageLikeEvent<C> where
341    C::Redacted: RedactedMessageLikeEventContent
342{
343}
344
345/// A possibly-redacted message-like event without a `room_id`.
346///
347/// `SyncMessageLikeEvent` implements the comparison traits using only the `event_id` field, a
348/// sorted list would be sorted lexicographically based on the event's `EventId`.
349#[allow(clippy::exhaustive_enums)]
350#[derive(Clone, Debug)]
351pub enum SyncMessageLikeEvent<C: MessageLikeEventContent + RedactContent>
352where
353    C::Redacted: RedactedMessageLikeEventContent,
354{
355    /// Original, unredacted form of the event.
356    Original(OriginalSyncMessageLikeEvent<C>),
357
358    /// Redacted form of the event with minimal fields.
359    Redacted(RedactedSyncMessageLikeEvent<C::Redacted>),
360}
361
362impl<C: MessageLikeEventContent + RedactContent> JsonCastable<JsonObject>
363    for SyncMessageLikeEvent<C>
364where
365    C::Redacted: RedactedMessageLikeEventContent,
366{
367}
368
369/// An unredacted state event.
370///
371/// `OriginalStateEvent` implements the comparison traits using only the `event_id` field, a sorted
372/// list would be sorted lexicographically based on the event's `EventId`.
373#[derive(Clone, Debug, Event)]
374#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
375pub struct OriginalStateEvent<C: StaticStateEventContent> {
376    /// Data specific to the event type.
377    pub content: C,
378
379    /// The globally unique identifier for the event.
380    pub event_id: OwnedEventId,
381
382    /// The fully-qualified ID of the user who sent this event.
383    pub sender: OwnedUserId,
384
385    /// Timestamp on the originating homeserver when this event was sent.
386    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
387
388    /// The ID of the room associated with this event.
389    pub room_id: OwnedRoomId,
390
391    /// A unique key which defines the overwriting semantics for this piece of room state.
392    ///
393    /// This must be a string type, and is often an empty string.
394    ///
395    /// A state event is keyed by its `(type, state_key)` tuple. Sending another state event with
396    /// the same tuple replaces the previous one.
397    pub state_key: C::StateKey,
398
399    /// Additional key-value pairs not signed by the homeserver.
400    pub unsigned: C::Unsigned,
401}
402
403impl<C: StaticStateEventContent> JsonCastable<OriginalSyncStateEvent<C>> for OriginalStateEvent<C> {}
404
405impl<C: StaticStateEventContent + RedactContent> JsonCastable<StateEvent<C>>
406    for OriginalStateEvent<C>
407where
408    C::Redacted: RedactedStateEventContent,
409{
410}
411
412impl<C: StaticStateEventContent + RedactContent> JsonCastable<SyncStateEvent<C>>
413    for OriginalStateEvent<C>
414where
415    C::Redacted: RedactedStateEventContent,
416{
417}
418
419impl<C: StaticStateEventContent> JsonCastable<StrippedStateEvent<C::PossiblyRedacted>>
420    for OriginalStateEvent<C>
421where
422    C::PossiblyRedacted: PossiblyRedactedStateEventContent,
423{
424}
425
426impl<C: StaticStateEventContent> JsonCastable<JsonObject> for OriginalStateEvent<C> {}
427
428/// An unredacted state event without a `room_id`.
429///
430/// `OriginalSyncStateEvent` implements the comparison traits using only the `event_id` field, a
431/// sorted list would be sorted lexicographically based on the event's `EventId`.
432#[derive(Clone, Debug, Event)]
433#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
434pub struct OriginalSyncStateEvent<C: StaticStateEventContent> {
435    /// Data specific to the event type.
436    pub content: C,
437
438    /// The globally unique identifier for the event.
439    pub event_id: OwnedEventId,
440
441    /// The fully-qualified ID of the user who sent this event.
442    pub sender: OwnedUserId,
443
444    /// Timestamp on the originating homeserver when this event was sent.
445    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
446
447    /// A unique key which defines the overwriting semantics for this piece of room state.
448    ///
449    /// This must be a string type, and is often an empty string.
450    ///
451    /// A state event is keyed by its `(type, state_key)` tuple. Sending another state event with
452    /// the same tuple replaces the previous one.
453    pub state_key: C::StateKey,
454
455    /// Additional key-value pairs not signed by the homeserver.
456    pub unsigned: C::Unsigned,
457}
458
459impl<C: StaticStateEventContent + RedactContent> JsonCastable<SyncStateEvent<C>>
460    for OriginalSyncStateEvent<C>
461where
462    C::Redacted: RedactedStateEventContent,
463{
464}
465
466impl<C: StaticStateEventContent> JsonCastable<StrippedStateEvent<C::PossiblyRedacted>>
467    for OriginalSyncStateEvent<C>
468where
469    C::PossiblyRedacted: PossiblyRedactedStateEventContent,
470{
471}
472
473impl<C: StaticStateEventContent> JsonCastable<JsonObject> for OriginalSyncStateEvent<C> {}
474
475/// A stripped-down state event, used for previews of rooms the user has been invited to.
476#[derive(Clone, Debug, Event)]
477#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
478pub struct StrippedStateEvent<C: PossiblyRedactedStateEventContent> {
479    /// Data specific to the event type.
480    pub content: C,
481
482    /// The fully-qualified ID of the user who sent this event.
483    pub sender: OwnedUserId,
484
485    /// A unique key which defines the overwriting semantics for this piece of room state.
486    ///
487    /// This must be a string type, and is often an empty string.
488    ///
489    /// A state event is keyed by its `(type, state_key)` tuple. Sending another state event with
490    /// the same tuple replaces the previous one.
491    pub state_key: C::StateKey,
492
493    /// Timestamp on the originating homeserver when this event was sent.
494    ///
495    /// This field is usually stripped, but some events might include it.
496    #[cfg(feature = "unstable-msc4319")]
497    #[ruma_event(default)]
498    pub origin_server_ts: Option<MilliSecondsSinceUnixEpoch>,
499
500    /// Additional key-value pairs not signed by the homeserver.
501    #[cfg(feature = "unstable-msc4319")]
502    pub unsigned: Option<Raw<crate::StateUnsigned<C>>>,
503}
504
505impl<C: PossiblyRedactedStateEventContent> JsonCastable<JsonObject> for StrippedStateEvent<C> {}
506
507/// A minimal state event, used for creating a new room.
508#[derive(Clone, Debug, Event)]
509#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
510pub struct InitialStateEvent<C: StaticStateEventContent> {
511    /// Data specific to the event type.
512    pub content: C,
513
514    /// A unique key which defines the overwriting semantics for this piece of room state.
515    ///
516    /// This must be a string type, and is often an empty string.
517    ///
518    /// A state event is keyed by its `(type, state_key)` tuple. Sending another state event with
519    /// the same tuple replaces the previous one.
520    ///
521    /// Defaults to the empty string.
522    pub state_key: C::StateKey,
523}
524
525impl<C: StaticStateEventContent> InitialStateEvent<C> {
526    /// Create a new `InitialStateEvent` for an event type with the given state key.
527    ///
528    /// For cases where the state key is empty,
529    /// [`with_empty_state_key()`](Self::with_empty_state_key) can be used instead.
530    pub fn new(state_key: C::StateKey, content: C) -> Self {
531        Self { content, state_key }
532    }
533
534    /// Create a new `InitialStateEvent` for an event type with an empty state key.
535    ///
536    /// For cases where the state key is not empty, use [`new()`](Self::new).
537    pub fn with_empty_state_key(content: C) -> Self
538    where
539        C: StaticStateEventContent<StateKey = EmptyStateKey>,
540    {
541        Self::new(EmptyStateKey, content)
542    }
543
544    /// Shorthand for `Raw::new(self).unwrap()`.
545    ///
546    /// Since none of the content types in Ruma ever return an error in serialization, this will
547    /// never panic with `C` being a type from Ruma. However, if you use a custom content type
548    /// with a `Serialize` implementation that can error (for example because it contains an
549    /// `enum` with one or more variants that use the `#[serde(skip)]` attribute), this method
550    /// can panic.
551    pub fn to_raw(&self) -> Raw<Self> {
552        Raw::new(self).unwrap()
553    }
554
555    /// Shorthand for `self.to_raw().cast::<AnyInitialStateEvent>()`.
556    ///
557    /// Since none of the content types in Ruma ever return an error in serialization, this will
558    /// never panic with `C` being a type from Ruma. However, if you use a custom content type
559    /// with a `Serialize` implementation that can error (for example because it contains an
560    /// `enum` with one or more variants that use the `#[serde(skip)]` attribute), this method
561    /// can panic.
562    pub fn to_raw_any(&self) -> Raw<AnyInitialStateEvent> {
563        self.to_raw().cast()
564    }
565}
566
567impl<C> Default for InitialStateEvent<C>
568where
569    C: StaticStateEventContent<StateKey = EmptyStateKey> + Default,
570{
571    fn default() -> Self {
572        Self { content: Default::default(), state_key: EmptyStateKey }
573    }
574}
575
576impl<C: StaticStateEventContent> Serialize for InitialStateEvent<C> {
577    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
578    where
579        S: serde::Serializer,
580    {
581        let mut state = serializer.serialize_struct("InitialStateEvent", 3)?;
582        state.serialize_field("type", &self.content.event_type())?;
583        state.serialize_field("content", &self.content)?;
584        state.serialize_field("state_key", &self.state_key)?;
585        state.end()
586    }
587}
588
589impl<C: StaticStateEventContent> JsonCastable<JsonObject> for InitialStateEvent<C> {}
590
591/// A redacted state event.
592///
593/// `RedactedStateEvent` implements the comparison traits using only the `event_id` field, a sorted
594/// list would be sorted lexicographically based on the event's `EventId`.
595#[derive(Clone, Debug, Event)]
596#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
597pub struct RedactedStateEvent<C: RedactedStateEventContent> {
598    /// Data specific to the event type.
599    pub content: C,
600
601    /// The globally unique identifier for the event.
602    pub event_id: OwnedEventId,
603
604    /// The fully-qualified ID of the user who sent this event.
605    pub sender: OwnedUserId,
606
607    /// Timestamp on the originating homeserver when this event was sent.
608    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
609
610    /// The ID of the room associated with this event.
611    pub room_id: OwnedRoomId,
612
613    /// A unique key which defines the overwriting semantics for this piece of room state.
614    ///
615    /// This must be a string type, and is often an empty string.
616    ///
617    /// A state event is keyed by its `(type, state_key)` tuple. Sending another state event with
618    /// the same tuple replaces the previous one.
619    pub state_key: C::StateKey,
620
621    /// Additional key-value pairs not signed by the homeserver.
622    pub unsigned: RedactedUnsigned,
623}
624
625impl<C: RedactedStateEventContent> JsonCastable<RedactedSyncStateEvent<C>>
626    for RedactedStateEvent<C>
627{
628}
629
630impl<C: StaticStateEventContent + RedactContent> JsonCastable<StateEvent<C>>
631    for RedactedStateEvent<C::Redacted>
632where
633    C::Redacted: RedactedStateEventContent,
634{
635}
636
637impl<C: StaticStateEventContent + RedactContent> JsonCastable<SyncStateEvent<C>>
638    for RedactedStateEvent<C::Redacted>
639where
640    C::Redacted: RedactedStateEventContent,
641{
642}
643
644impl<C: RedactedStateEventContent> JsonCastable<JsonObject> for RedactedStateEvent<C> {}
645
646/// A redacted state event without a `room_id`.
647///
648/// `RedactedSyncStateEvent` implements the comparison traits using only the `event_id` field, a
649/// sorted list would be sorted lexicographically based on the event's `EventId`.
650#[derive(Clone, Debug, Event)]
651#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
652pub struct RedactedSyncStateEvent<C: RedactedStateEventContent> {
653    /// Data specific to the event type.
654    pub content: C,
655
656    /// The globally unique identifier for the event.
657    pub event_id: OwnedEventId,
658
659    /// The fully-qualified ID of the user who sent this event.
660    pub sender: OwnedUserId,
661
662    /// Timestamp on the originating homeserver when this event was sent.
663    pub origin_server_ts: MilliSecondsSinceUnixEpoch,
664
665    /// A unique key which defines the overwriting semantics for this piece of room state.
666    ///
667    /// This must be a string type, and is often an empty string.
668    ///
669    /// A state event is keyed by its `(type, state_key)` tuple. Sending another state event with
670    /// the same tuple replaces the previous one.
671    pub state_key: C::StateKey,
672
673    /// Additional key-value pairs not signed by the homeserver.
674    pub unsigned: RedactedUnsigned,
675}
676
677impl<C: StaticStateEventContent + RedactContent> JsonCastable<SyncStateEvent<C>>
678    for RedactedSyncStateEvent<C::Redacted>
679where
680    C::Redacted: RedactedStateEventContent,
681{
682}
683
684impl<C: RedactedStateEventContent> JsonCastable<JsonObject> for RedactedSyncStateEvent<C> {}
685
686/// A possibly-redacted state event.
687///
688/// `StateEvent` implements the comparison traits using only the `event_id` field, a sorted list
689/// would be sorted lexicographically based on the event's `EventId`.
690#[allow(clippy::exhaustive_enums)]
691#[derive(Clone, Debug)]
692pub enum StateEvent<C: StaticStateEventContent + RedactContent>
693where
694    C::Redacted: RedactedStateEventContent,
695{
696    /// Original, unredacted form of the event.
697    Original(OriginalStateEvent<C>),
698
699    /// Redacted form of the event with minimal fields.
700    Redacted(RedactedStateEvent<C::Redacted>),
701}
702
703impl<C: StaticStateEventContent + RedactContent> JsonCastable<SyncStateEvent<C>> for StateEvent<C> where
704    C::Redacted: RedactedStateEventContent
705{
706}
707
708impl<C: StaticStateEventContent + RedactContent>
709    JsonCastable<StrippedStateEvent<C::PossiblyRedacted>> for StateEvent<C>
710where
711    C::Redacted: RedactedStateEventContent,
712    C::PossiblyRedacted: PossiblyRedactedStateEventContent,
713{
714}
715
716impl<C: StaticStateEventContent + RedactContent> JsonCastable<JsonObject> for StateEvent<C> where
717    C::Redacted: RedactedStateEventContent
718{
719}
720
721/// A possibly-redacted state event without a `room_id`.
722///
723/// `SyncStateEvent` implements the comparison traits using only the `event_id` field, a sorted list
724/// would be sorted lexicographically based on the event's `EventId`.
725#[allow(clippy::exhaustive_enums)]
726#[derive(Clone, Debug)]
727pub enum SyncStateEvent<C: StaticStateEventContent + RedactContent>
728where
729    C::Redacted: RedactedStateEventContent,
730{
731    /// Original, unredacted form of the event.
732    Original(OriginalSyncStateEvent<C>),
733
734    /// Redacted form of the event with minimal fields.
735    Redacted(RedactedSyncStateEvent<C::Redacted>),
736}
737
738impl<C: StaticStateEventContent + RedactContent>
739    JsonCastable<StrippedStateEvent<C::PossiblyRedacted>> for SyncStateEvent<C>
740where
741    C::Redacted: RedactedStateEventContent,
742    C::PossiblyRedacted: PossiblyRedactedStateEventContent,
743{
744}
745
746impl<C: StaticStateEventContent + RedactContent> JsonCastable<JsonObject> for SyncStateEvent<C> where
747    C::Redacted: RedactedStateEventContent
748{
749}
750
751/// An event sent using send-to-device messaging.
752#[derive(Clone, Debug, Event)]
753#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
754pub struct ToDeviceEvent<C: ToDeviceEventContent> {
755    /// Data specific to the event type.
756    pub content: C,
757
758    /// The fully-qualified ID of the user who sent this event.
759    pub sender: OwnedUserId,
760}
761
762impl<C: ToDeviceEventContent> ToDeviceEvent<C> {
763    /// Construct a new `ToDeviceEvent` with the given content and sender.
764    pub fn new(sender: OwnedUserId, content: C) -> Self {
765        Self { content, sender }
766    }
767}
768
769impl<C: ToDeviceEventContent> Serialize for ToDeviceEvent<C> {
770    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
771    where
772        S: serde::Serializer,
773    {
774        let mut state = serializer.serialize_struct("ToDeviceEvent", 3)?;
775        state.serialize_field("type", &self.content.event_type())?;
776        state.serialize_field("content", &self.content)?;
777        state.serialize_field("sender", &self.sender)?;
778        state.end()
779    }
780}
781
782impl<C: ToDeviceEventContent> JsonCastable<JsonObject> for ToDeviceEvent<C> {}
783
784/// The decrypted payload of an `m.olm.v1.curve25519-aes-sha2` event.
785#[derive(Clone, Debug, Event)]
786#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
787pub struct DecryptedOlmV1Event<C: MessageLikeEventContent> {
788    /// Data specific to the event type.
789    pub content: C,
790
791    /// The fully-qualified ID of the user who sent this event.
792    pub sender: OwnedUserId,
793
794    /// The fully-qualified ID of the intended recipient this event.
795    pub recipient: OwnedUserId,
796
797    /// The recipient's ed25519 key.
798    pub recipient_keys: OlmV1Keys,
799
800    /// The sender's ed25519 key.
801    pub keys: OlmV1Keys,
802
803    /// The sender's device keys.
804    pub sender_device_keys: Option<Raw<DeviceKeys>>,
805}
806
807/// Public keys used for an `m.olm.v1.curve25519-aes-sha2` event.
808#[derive(Clone, Debug, Deserialize, Serialize)]
809#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
810pub struct OlmV1Keys {
811    /// An ed25519 key.
812    pub ed25519: String,
813}
814
815impl OlmV1Keys {
816    /// Construct a new `OlmV1Keys` with the given ed25519 key.
817    pub fn new(ed25519: String) -> Self {
818        Self { ed25519 }
819    }
820}
821
822/// The decrypted payload of an `m.megolm.v1.aes-sha2` event.
823#[derive(Clone, Debug, Event)]
824#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
825pub struct DecryptedMegolmV1Event<C: MessageLikeEventContent> {
826    /// Data specific to the event type.
827    pub content: C,
828
829    /// The ID of the room associated with the event.
830    pub room_id: OwnedRoomId,
831}
832
833/// A possibly-redacted state event content and the corresponding previous content from the unsigned
834/// event data, if available.
835#[allow(clippy::exhaustive_enums)]
836#[derive(Clone, Debug)]
837pub enum StateEventContentChange<C: StaticStateEventContent + RedactContent> {
838    /// Original, unredacted content of the event.
839    Original {
840        /// Current content of the room state.
841        content: C,
842
843        /// Previous content of the room state.
844        prev_content: Option<C::PossiblyRedacted>,
845    },
846
847    /// Redacted content of the event.
848    Redacted(C::Redacted),
849}
850
851impl<C: StaticStateEventContent + RedactContent> StateEventContentChange<C>
852where
853    C::Redacted: RedactedStateEventContent,
854{
855    /// Get the event’s type, like `m.room.create`.
856    pub fn event_type(&self) -> StateEventType {
857        match self {
858            Self::Original { content, .. } => content.event_type(),
859            Self::Redacted(content) => content.event_type(),
860        }
861    }
862
863    /// Transform `self` into a redacted form (removing most or all fields) according to the spec.
864    ///
865    /// If `self` is already [`Redacted`](Self::Redacted), return the inner data unmodified.
866    ///
867    /// A small number of events have room-version specific redaction behavior, so a
868    /// [`RedactionRules`] has to be specified.
869    pub fn redact(self, rules: &RedactionRules) -> C::Redacted {
870        match self {
871            Self::Original { content, .. } => content.redact(rules),
872            Self::Redacted(content) => content,
873        }
874    }
875}
876
877macro_rules! impl_possibly_redacted_event {
878    (
879        $ty:ident ( $content_trait:ident, $redacted_content_trait:ident, $event_type:ident )
880        $( where C::Redacted: $trait:ident<StateKey = C::StateKey>, )?
881        { $($extra:tt)* }
882    ) => {
883        impl<C> $ty<C>
884        where
885            C: $content_trait + RedactContent,
886            C::Redacted: $redacted_content_trait,
887            $( C::Redacted: $trait<StateKey = C::StateKey>, )?
888        {
889            /// Returns the `type` of this event.
890            pub fn event_type(&self) -> $event_type {
891                match self {
892                    Self::Original(ev) => ev.content.event_type(),
893                    Self::Redacted(ev) => ev.content.event_type(),
894                }
895            }
896
897            /// Returns this event's `event_id` field.
898            pub fn event_id(&self) -> &EventId {
899                match self {
900                    Self::Original(ev) => &ev.event_id,
901                    Self::Redacted(ev) => &ev.event_id,
902                }
903            }
904
905            /// Returns this event's `sender` field.
906            pub fn sender(&self) -> &UserId {
907                match self {
908                    Self::Original(ev) => &ev.sender,
909                    Self::Redacted(ev) => &ev.sender,
910                }
911            }
912
913            /// Returns this event's `origin_server_ts` field.
914            pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
915                match self {
916                    Self::Original(ev) => ev.origin_server_ts,
917                    Self::Redacted(ev) => ev.origin_server_ts,
918                }
919            }
920
921            // So the room_id method can be in the same impl block, in rustdoc
922            $($extra)*
923        }
924
925        impl<'de, C> Deserialize<'de> for $ty<C>
926        where
927            C: $content_trait + EventContentFromType + RedactContent,
928            C::Redacted: $redacted_content_trait + EventContentFromType,
929            $( C::Redacted: $trait<StateKey = C::StateKey>, )?
930        {
931            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
932            where
933                D: Deserializer<'de>,
934            {
935                let json = Box::<RawJsonValue>::deserialize(deserializer)?;
936                let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;
937
938                if unsigned.and_then(|u| u.redacted_because).is_some() {
939                    Ok(Self::Redacted(from_raw_json_value(&json)?))
940                } else {
941                    Ok(Self::Original(from_raw_json_value(&json)?))
942                }
943            }
944        }
945    }
946}
947
948impl_possibly_redacted_event!(
949    MessageLikeEvent(
950        MessageLikeEventContent, RedactedMessageLikeEventContent, MessageLikeEventType
951    ) {
952        /// Returns this event's `room_id` field.
953        pub fn room_id(&self) -> &RoomId {
954            match self {
955                Self::Original(ev) => &ev.room_id,
956                Self::Redacted(ev) => &ev.room_id,
957            }
958        }
959
960        /// Get the inner `OriginalMessageLikeEvent` if this is an unredacted event.
961        pub fn as_original(&self) -> Option<&OriginalMessageLikeEvent<C>> {
962            as_variant!(self, Self::Original)
963        }
964    }
965);
966
967impl_possibly_redacted_event!(
968    SyncMessageLikeEvent(
969        MessageLikeEventContent, RedactedMessageLikeEventContent, MessageLikeEventType
970    ) {
971        /// Get the inner `OriginalSyncMessageLikeEvent` if this is an unredacted event.
972        pub fn as_original(&self) -> Option<&OriginalSyncMessageLikeEvent<C>> {
973            as_variant!(self, Self::Original)
974        }
975
976        /// Convert this sync event into a full event (one with a `room_id` field).
977        pub fn into_full_event(self, room_id: OwnedRoomId) -> MessageLikeEvent<C> {
978            match self {
979                Self::Original(ev) => MessageLikeEvent::Original(ev.into_full_event(room_id)),
980                Self::Redacted(ev) => MessageLikeEvent::Redacted(ev.into_full_event(room_id)),
981            }
982        }
983    }
984);
985
986impl_possibly_redacted_event!(
987    StateEvent(StaticStateEventContent, RedactedStateEventContent, StateEventType)
988    where
989        C::Redacted: RedactedStateEventContent<StateKey = C::StateKey>,
990    {
991        /// Returns this event's `room_id` field.
992        pub fn room_id(&self) -> &RoomId {
993            match self {
994                Self::Original(ev) => &ev.room_id,
995                Self::Redacted(ev) => &ev.room_id,
996            }
997        }
998
999        /// Returns this event's `state_key` field.
1000        pub fn state_key(&self) -> &C::StateKey {
1001            match self {
1002                Self::Original(ev) => &ev.state_key,
1003                Self::Redacted(ev) => &ev.state_key,
1004            }
1005        }
1006
1007        /// Get the inner `OriginalStateEvent` if this is an unredacted event.
1008        pub fn as_original(&self) -> Option<&OriginalStateEvent<C>> {
1009            as_variant!(self, Self::Original)
1010        }
1011    }
1012);
1013
1014impl_possibly_redacted_event!(
1015    SyncStateEvent(StaticStateEventContent, RedactedStateEventContent, StateEventType)
1016    where
1017        C::Redacted: RedactedStateEventContent<StateKey = C::StateKey>,
1018    {
1019        /// Returns this event's `state_key` field.
1020        pub fn state_key(&self) -> &C::StateKey {
1021            match self {
1022                Self::Original(ev) => &ev.state_key,
1023                Self::Redacted(ev) => &ev.state_key,
1024            }
1025        }
1026
1027        /// Get the inner `OriginalSyncStateEvent` if this is an unredacted event.
1028        pub fn as_original(&self) -> Option<&OriginalSyncStateEvent<C>> {
1029            as_variant!(self, Self::Original)
1030        }
1031
1032        /// Convert this sync event into a full event (one with a `room_id` field).
1033        pub fn into_full_event(self, room_id: OwnedRoomId) -> StateEvent<C> {
1034            match self {
1035                Self::Original(ev) => StateEvent::Original(ev.into_full_event(room_id)),
1036                Self::Redacted(ev) => StateEvent::Redacted(ev.into_full_event(room_id)),
1037            }
1038        }
1039    }
1040);
1041
1042macro_rules! impl_sync_from_full {
1043    ($ty:ident, $full:ident, $content_trait:ident, $redacted_content_trait: ident) => {
1044        impl<C> From<$full<C>> for $ty<C>
1045        where
1046            C: $content_trait + RedactContent,
1047            C::Redacted: $redacted_content_trait,
1048        {
1049            fn from(full: $full<C>) -> Self {
1050                match full {
1051                    $full::Original(ev) => Self::Original(ev.into()),
1052                    $full::Redacted(ev) => Self::Redacted(ev.into()),
1053                }
1054            }
1055        }
1056    };
1057}
1058
1059impl_sync_from_full!(
1060    SyncMessageLikeEvent,
1061    MessageLikeEvent,
1062    MessageLikeEventContent,
1063    RedactedMessageLikeEventContent
1064);
1065impl_sync_from_full!(
1066    SyncStateEvent,
1067    StateEvent,
1068    StaticStateEventContent,
1069    RedactedStateEventContent
1070);