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