matrix_sdk_base/
utils.rs

1use ruma::{
2    assign,
3    events::{
4        room::{
5            avatar::{RoomAvatarEventContent, StrippedRoomAvatarEvent},
6            canonical_alias::{RoomCanonicalAliasEventContent, StrippedRoomCanonicalAliasEvent},
7            create::{StrippedRoomCreateEvent, SyncRoomCreateEvent},
8            guest_access::{
9                RedactedRoomGuestAccessEventContent, RoomGuestAccessEventContent,
10                StrippedRoomGuestAccessEvent,
11            },
12            history_visibility::{
13                RoomHistoryVisibilityEventContent, StrippedRoomHistoryVisibilityEvent,
14            },
15            join_rules::{RoomJoinRulesEventContent, StrippedRoomJoinRulesEvent},
16            member::{MembershipState, RoomMemberEventContent},
17            name::{RedactedRoomNameEventContent, RoomNameEventContent, StrippedRoomNameEvent},
18            tombstone::{
19                RedactedRoomTombstoneEventContent, RoomTombstoneEventContent,
20                StrippedRoomTombstoneEvent,
21            },
22            topic::{RedactedRoomTopicEventContent, RoomTopicEventContent, StrippedRoomTopicEvent},
23        },
24        RedactContent, RedactedStateEventContent, StateEventContent, StaticStateEventContent,
25        SyncStateEvent,
26    },
27    EventId, OwnedEventId, RoomVersionId,
28};
29use serde::{de::DeserializeOwned, Deserialize, Serialize};
30
31use crate::rooms::RoomCreateWithCreatorEventContent;
32
33// #[serde(bound)] instead of DeserializeOwned in type where clause does not
34// work, it can only be a single bound that replaces the default and if a helper
35// trait is used, the compiler still complains about Deserialize not being
36// implemented for C::Redacted.
37//
38// It is unclear why a Serialize bound on C::Redacted is not also required.
39
40/// A minimal state event.
41///
42/// This type can holding an possibly-redacted state event with an optional
43/// event ID. The event ID is optional so this type can also hold events from
44/// invited rooms, where event IDs are not available.
45#[derive(Clone, Debug, Deserialize, Serialize)]
46#[serde(bound(
47    serialize = "C: Serialize, C::Redacted: Serialize",
48    deserialize = "C: DeserializeOwned, C::Redacted: DeserializeOwned"
49))]
50pub enum MinimalStateEvent<C: StateEventContent + RedactContent>
51where
52    C::Redacted: RedactedStateEventContent,
53{
54    /// An unredacted event.
55    Original(OriginalMinimalStateEvent<C>),
56    /// A redacted event.
57    Redacted(RedactedMinimalStateEvent<C::Redacted>),
58}
59
60/// An unredacted minimal state event.
61///
62/// For more details see [`MinimalStateEvent`].
63#[derive(Clone, Debug, Deserialize, Serialize)]
64pub struct OriginalMinimalStateEvent<C>
65where
66    C: StateEventContent,
67{
68    /// The event's content.
69    pub content: C,
70    /// The event's ID, if known.
71    pub event_id: Option<OwnedEventId>,
72}
73
74/// A redacted minimal state event.
75///
76/// For more details see [`MinimalStateEvent`].
77#[derive(Clone, Debug, Deserialize, Serialize)]
78pub struct RedactedMinimalStateEvent<C>
79where
80    C: RedactedStateEventContent,
81{
82    /// The event's content.
83    pub content: C,
84    /// The event's ID, if known.
85    pub event_id: Option<OwnedEventId>,
86}
87
88impl<C> MinimalStateEvent<C>
89where
90    C: StateEventContent + RedactContent,
91    C::Redacted: RedactedStateEventContent,
92{
93    /// Get the inner event's ID.
94    pub fn event_id(&self) -> Option<&EventId> {
95        match self {
96            MinimalStateEvent::Original(ev) => ev.event_id.as_deref(),
97            MinimalStateEvent::Redacted(ev) => ev.event_id.as_deref(),
98        }
99    }
100
101    /// Returns the inner event, if it isn't redacted.
102    pub fn as_original(&self) -> Option<&OriginalMinimalStateEvent<C>> {
103        match self {
104            MinimalStateEvent::Original(ev) => Some(ev),
105            MinimalStateEvent::Redacted(_) => None,
106        }
107    }
108
109    /// Converts `self` to the inner `OriginalMinimalStateEvent<C>`, if it isn't
110    /// redacted.
111    pub fn into_original(self) -> Option<OriginalMinimalStateEvent<C>> {
112        match self {
113            MinimalStateEvent::Original(ev) => Some(ev),
114            MinimalStateEvent::Redacted(_) => None,
115        }
116    }
117
118    /// Redacts this event.
119    ///
120    /// Does nothing if it is already redacted.
121    pub fn redact(&mut self, room_version: &RoomVersionId)
122    where
123        C: Clone,
124    {
125        if let MinimalStateEvent::Original(ev) = self {
126            *self = MinimalStateEvent::Redacted(RedactedMinimalStateEvent {
127                content: ev.content.clone().redact(room_version),
128                event_id: ev.event_id.clone(),
129            });
130        }
131    }
132}
133
134/// A minimal `m.room.member` event.
135pub type MinimalRoomMemberEvent = MinimalStateEvent<RoomMemberEventContent>;
136
137impl MinimalRoomMemberEvent {
138    /// Obtain the membership state, regardless of whether this event is
139    /// redacted.
140    pub fn membership(&self) -> &MembershipState {
141        match self {
142            MinimalStateEvent::Original(ev) => &ev.content.membership,
143            MinimalStateEvent::Redacted(ev) => &ev.content.membership,
144        }
145    }
146}
147
148impl<C> From<SyncStateEvent<C>> for MinimalStateEvent<C>
149where
150    C: StaticStateEventContent + RedactContent,
151    C::Redacted: RedactedStateEventContent,
152{
153    fn from(ev: SyncStateEvent<C>) -> Self {
154        match ev {
155            SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent {
156                content: ev.content,
157                event_id: Some(ev.event_id),
158            }),
159            SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent {
160                content: ev.content,
161                event_id: Some(ev.event_id),
162            }),
163        }
164    }
165}
166
167impl<C> From<&SyncStateEvent<C>> for MinimalStateEvent<C>
168where
169    C: Clone + StaticStateEventContent + RedactContent,
170    C::Redacted: Clone + RedactedStateEventContent,
171{
172    fn from(ev: &SyncStateEvent<C>) -> Self {
173        match ev {
174            SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent {
175                content: ev.content.clone(),
176                event_id: Some(ev.event_id.clone()),
177            }),
178            SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent {
179                content: ev.content.clone(),
180                event_id: Some(ev.event_id.clone()),
181            }),
182        }
183    }
184}
185
186impl From<&SyncRoomCreateEvent> for MinimalStateEvent<RoomCreateWithCreatorEventContent> {
187    fn from(ev: &SyncRoomCreateEvent) -> Self {
188        match ev {
189            SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent {
190                content: RoomCreateWithCreatorEventContent::from_event_content(
191                    ev.content.clone(),
192                    ev.sender.clone(),
193                ),
194                event_id: Some(ev.event_id.clone()),
195            }),
196            SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent {
197                content: RoomCreateWithCreatorEventContent::from_event_content(
198                    ev.content.clone(),
199                    ev.sender.clone(),
200                ),
201                event_id: Some(ev.event_id.clone()),
202            }),
203        }
204    }
205}
206
207impl From<&StrippedRoomAvatarEvent> for MinimalStateEvent<RoomAvatarEventContent> {
208    fn from(event: &StrippedRoomAvatarEvent) -> Self {
209        let content = assign!(RoomAvatarEventContent::new(), {
210            info: event.content.info.clone(),
211            url: event.content.url.clone(),
212        });
213        // event might actually be redacted, there is no way to tell for
214        // stripped state events.
215        Self::Original(OriginalMinimalStateEvent { content, event_id: None })
216    }
217}
218
219impl From<&StrippedRoomNameEvent> for MinimalStateEvent<RoomNameEventContent> {
220    fn from(event: &StrippedRoomNameEvent) -> Self {
221        match event.content.name.clone() {
222            Some(name) => {
223                let content = RoomNameEventContent::new(name);
224                Self::Original(OriginalMinimalStateEvent { content, event_id: None })
225            }
226            None => {
227                let content = RedactedRoomNameEventContent::new();
228                Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
229            }
230        }
231    }
232}
233
234impl From<&StrippedRoomCreateEvent> for MinimalStateEvent<RoomCreateWithCreatorEventContent> {
235    fn from(event: &StrippedRoomCreateEvent) -> Self {
236        let content = RoomCreateWithCreatorEventContent {
237            creator: event.sender.clone(),
238            federate: event.content.federate,
239            room_version: event.content.room_version.clone(),
240            predecessor: event.content.predecessor.clone(),
241            room_type: event.content.room_type.clone(),
242        };
243        Self::Original(OriginalMinimalStateEvent { content, event_id: None })
244    }
245}
246
247impl From<&StrippedRoomHistoryVisibilityEvent>
248    for MinimalStateEvent<RoomHistoryVisibilityEventContent>
249{
250    fn from(event: &StrippedRoomHistoryVisibilityEvent) -> Self {
251        let content =
252            RoomHistoryVisibilityEventContent::new(event.content.history_visibility.clone());
253        Self::Original(OriginalMinimalStateEvent { content, event_id: None })
254    }
255}
256
257impl From<&StrippedRoomGuestAccessEvent> for MinimalStateEvent<RoomGuestAccessEventContent> {
258    fn from(event: &StrippedRoomGuestAccessEvent) -> Self {
259        match &event.content.guest_access {
260            Some(guest_access) => {
261                let content = RoomGuestAccessEventContent::new(guest_access.clone());
262                Self::Original(OriginalMinimalStateEvent { content, event_id: None })
263            }
264            None => {
265                let content = RedactedRoomGuestAccessEventContent::new();
266                Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
267            }
268        }
269    }
270}
271
272impl From<&StrippedRoomJoinRulesEvent> for MinimalStateEvent<RoomJoinRulesEventContent> {
273    fn from(event: &StrippedRoomJoinRulesEvent) -> Self {
274        let content = RoomJoinRulesEventContent::new(event.content.join_rule.clone());
275        Self::Original(OriginalMinimalStateEvent { content, event_id: None })
276    }
277}
278
279impl From<&StrippedRoomCanonicalAliasEvent> for MinimalStateEvent<RoomCanonicalAliasEventContent> {
280    fn from(event: &StrippedRoomCanonicalAliasEvent) -> Self {
281        let content = assign!(RoomCanonicalAliasEventContent::new(), {
282            alias: event.content.alias.clone(),
283            alt_aliases: event.content.alt_aliases.clone(),
284        });
285        Self::Original(OriginalMinimalStateEvent { content, event_id: None })
286    }
287}
288
289impl From<&StrippedRoomTopicEvent> for MinimalStateEvent<RoomTopicEventContent> {
290    fn from(event: &StrippedRoomTopicEvent) -> Self {
291        match &event.content.topic {
292            Some(topic) => {
293                let content = RoomTopicEventContent::new(topic.clone());
294                Self::Original(OriginalMinimalStateEvent { content, event_id: None })
295            }
296            None => {
297                let content = RedactedRoomTopicEventContent::new();
298                Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
299            }
300        }
301    }
302}
303
304impl From<&StrippedRoomTombstoneEvent> for MinimalStateEvent<RoomTombstoneEventContent> {
305    fn from(event: &StrippedRoomTombstoneEvent) -> Self {
306        match (&event.content.body, &event.content.replacement_room) {
307            (Some(body), Some(replacement_room)) => {
308                let content =
309                    RoomTombstoneEventContent::new(body.clone(), replacement_room.clone());
310                Self::Original(OriginalMinimalStateEvent { content, event_id: None })
311            }
312            _ => {
313                let content = RedactedRoomTombstoneEventContent::new();
314                Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
315            }
316        }
317    }
318}