ruma_events/
kinds.rs

1use as_variant::as_variant;
2use ruma_common::{
3    encryption::DeviceKeys,
4    room_version_rules::RedactionRules,
5    serde::{from_raw_json_value, JsonCastable, JsonObject, Raw},
6    EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, UserId,
7};
8use ruma_macros::Event;
9use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize};
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.
834///
835/// A non-redacted content also contains the `prev_content` from the unsigned event data.
836#[allow(clippy::exhaustive_enums)]
837#[derive(Clone, Debug)]
838pub enum FullStateEventContent<C: StaticStateEventContent + RedactContent> {
839    /// Original, unredacted content of the event.
840    Original {
841        /// Current content of the room state.
842        content: C,
843
844        /// Previous content of the room state.
845        prev_content: Option<C::PossiblyRedacted>,
846    },
847
848    /// Redacted content of the event.
849    Redacted(C::Redacted),
850}
851
852impl<C: StaticStateEventContent + RedactContent> FullStateEventContent<C>
853where
854    C::Redacted: RedactedStateEventContent,
855{
856    /// Get the event’s type, like `m.room.create`.
857    pub fn event_type(&self) -> StateEventType {
858        match self {
859            Self::Original { content, .. } => content.event_type(),
860            Self::Redacted(content) => content.event_type(),
861        }
862    }
863
864    /// Transform `self` into a redacted form (removing most or all fields) according to the spec.
865    ///
866    /// If `self` is already [`Redacted`](Self::Redacted), return the inner data unmodified.
867    ///
868    /// A small number of events have room-version specific redaction behavior, so a
869    /// [`RedactionRules`] has to be specified.
870    pub fn redact(self, rules: &RedactionRules) -> C::Redacted {
871        match self {
872            FullStateEventContent::Original { content, .. } => content.redact(rules),
873            FullStateEventContent::Redacted(content) => content,
874        }
875    }
876}
877
878macro_rules! impl_possibly_redacted_event {
879    (
880        $ty:ident ( $content_trait:ident, $redacted_content_trait:ident, $event_type:ident )
881        $( where C::Redacted: $trait:ident<StateKey = C::StateKey>, )?
882        { $($extra:tt)* }
883    ) => {
884        impl<C> $ty<C>
885        where
886            C: $content_trait + RedactContent,
887            C::Redacted: $redacted_content_trait,
888            $( C::Redacted: $trait<StateKey = C::StateKey>, )?
889        {
890            /// Returns the `type` of this event.
891            pub fn event_type(&self) -> $event_type {
892                match self {
893                    Self::Original(ev) => ev.content.event_type(),
894                    Self::Redacted(ev) => ev.content.event_type(),
895                }
896            }
897
898            /// Returns this event's `event_id` field.
899            pub fn event_id(&self) -> &EventId {
900                match self {
901                    Self::Original(ev) => &ev.event_id,
902                    Self::Redacted(ev) => &ev.event_id,
903                }
904            }
905
906            /// Returns this event's `sender` field.
907            pub fn sender(&self) -> &UserId {
908                match self {
909                    Self::Original(ev) => &ev.sender,
910                    Self::Redacted(ev) => &ev.sender,
911                }
912            }
913
914            /// Returns this event's `origin_server_ts` field.
915            pub fn origin_server_ts(&self) -> MilliSecondsSinceUnixEpoch {
916                match self {
917                    Self::Original(ev) => ev.origin_server_ts,
918                    Self::Redacted(ev) => ev.origin_server_ts,
919                }
920            }
921
922            // So the room_id method can be in the same impl block, in rustdoc
923            $($extra)*
924        }
925
926        impl<'de, C> Deserialize<'de> for $ty<C>
927        where
928            C: $content_trait + EventContentFromType + RedactContent,
929            C::Redacted: $redacted_content_trait + EventContentFromType,
930            $( C::Redacted: $trait<StateKey = C::StateKey>, )?
931        {
932            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
933            where
934                D: Deserializer<'de>,
935            {
936                let json = Box::<RawJsonValue>::deserialize(deserializer)?;
937                let RedactionDeHelper { unsigned } = from_raw_json_value(&json)?;
938
939                if unsigned.and_then(|u| u.redacted_because).is_some() {
940                    Ok(Self::Redacted(from_raw_json_value(&json)?))
941                } else {
942                    Ok(Self::Original(from_raw_json_value(&json)?))
943                }
944            }
945        }
946    }
947}
948
949impl_possibly_redacted_event!(
950    MessageLikeEvent(
951        MessageLikeEventContent, RedactedMessageLikeEventContent, MessageLikeEventType
952    ) {
953        /// Returns this event's `room_id` field.
954        pub fn room_id(&self) -> &RoomId {
955            match self {
956                Self::Original(ev) => &ev.room_id,
957                Self::Redacted(ev) => &ev.room_id,
958            }
959        }
960
961        /// Get the inner `OriginalMessageLikeEvent` if this is an unredacted event.
962        pub fn as_original(&self) -> Option<&OriginalMessageLikeEvent<C>> {
963            as_variant!(self, Self::Original)
964        }
965    }
966);
967
968impl_possibly_redacted_event!(
969    SyncMessageLikeEvent(
970        MessageLikeEventContent, RedactedMessageLikeEventContent, MessageLikeEventType
971    ) {
972        /// Get the inner `OriginalSyncMessageLikeEvent` if this is an unredacted event.
973        pub fn as_original(&self) -> Option<&OriginalSyncMessageLikeEvent<C>> {
974            as_variant!(self, Self::Original)
975        }
976
977        /// Convert this sync event into a full event (one with a `room_id` field).
978        pub fn into_full_event(self, room_id: OwnedRoomId) -> MessageLikeEvent<C> {
979            match self {
980                Self::Original(ev) => MessageLikeEvent::Original(ev.into_full_event(room_id)),
981                Self::Redacted(ev) => MessageLikeEvent::Redacted(ev.into_full_event(room_id)),
982            }
983        }
984    }
985);
986
987impl_possibly_redacted_event!(
988    StateEvent(StaticStateEventContent, RedactedStateEventContent, StateEventType)
989    where
990        C::Redacted: RedactedStateEventContent<StateKey = C::StateKey>,
991    {
992        /// Returns this event's `room_id` field.
993        pub fn room_id(&self) -> &RoomId {
994            match self {
995                Self::Original(ev) => &ev.room_id,
996                Self::Redacted(ev) => &ev.room_id,
997            }
998        }
999
1000        /// Returns this event's `state_key` field.
1001        pub fn state_key(&self) -> &C::StateKey {
1002            match self {
1003                Self::Original(ev) => &ev.state_key,
1004                Self::Redacted(ev) => &ev.state_key,
1005            }
1006        }
1007
1008        /// Get the inner `OriginalStateEvent` if this is an unredacted event.
1009        pub fn as_original(&self) -> Option<&OriginalStateEvent<C>> {
1010            as_variant!(self, Self::Original)
1011        }
1012    }
1013);
1014
1015impl_possibly_redacted_event!(
1016    SyncStateEvent(StaticStateEventContent, RedactedStateEventContent, StateEventType)
1017    where
1018        C::Redacted: RedactedStateEventContent<StateKey = C::StateKey>,
1019    {
1020        /// Returns this event's `state_key` field.
1021        pub fn state_key(&self) -> &C::StateKey {
1022            match self {
1023                Self::Original(ev) => &ev.state_key,
1024                Self::Redacted(ev) => &ev.state_key,
1025            }
1026        }
1027
1028        /// Get the inner `OriginalSyncStateEvent` if this is an unredacted event.
1029        pub fn as_original(&self) -> Option<&OriginalSyncStateEvent<C>> {
1030            as_variant!(self, Self::Original)
1031        }
1032
1033        /// Convert this sync event into a full event (one with a `room_id` field).
1034        pub fn into_full_event(self, room_id: OwnedRoomId) -> StateEvent<C> {
1035            match self {
1036                Self::Original(ev) => StateEvent::Original(ev.into_full_event(room_id)),
1037                Self::Redacted(ev) => StateEvent::Redacted(ev.into_full_event(room_id)),
1038            }
1039        }
1040    }
1041);
1042
1043macro_rules! impl_sync_from_full {
1044    ($ty:ident, $full:ident, $content_trait:ident, $redacted_content_trait: ident) => {
1045        impl<C> From<$full<C>> for $ty<C>
1046        where
1047            C: $content_trait + RedactContent,
1048            C::Redacted: $redacted_content_trait,
1049        {
1050            fn from(full: $full<C>) -> Self {
1051                match full {
1052                    $full::Original(ev) => Self::Original(ev.into()),
1053                    $full::Redacted(ev) => Self::Redacted(ev.into()),
1054                }
1055            }
1056        }
1057    };
1058}
1059
1060impl_sync_from_full!(
1061    SyncMessageLikeEvent,
1062    MessageLikeEvent,
1063    MessageLikeEventContent,
1064    RedactedMessageLikeEventContent
1065);
1066impl_sync_from_full!(
1067    SyncStateEvent,
1068    StateEvent,
1069    StaticStateEventContent,
1070    RedactedStateEventContent
1071);