7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 1 | use ruma::{ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 2 | EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, UserId, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 3 | events::{ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 4 | AnyPossiblyRedactedStateEventContent, AnyStrippedStateEvent, AnySyncStateEvent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 5 | AnySyncTimelineEvent, PossiblyRedactedStateEventContent, RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 6 | RedactedStateEventContent, StateEventType, StaticEventContent, StaticStateEventContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 7 | StrippedStateEvent, SyncStateEvent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 8 | room::{ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 9 | create::{StrippedRoomCreateEvent, SyncRoomCreateEvent}, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 10 | member::PossiblyRedactedRoomMemberEventContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 11 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 12 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 13 | room_version_rules::RedactionRules, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 14 | serde::Raw, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 15 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 16 | use serde::{Deserialize, Serialize, de::DeserializeOwned}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 17 | use tracing::{error, warn}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 18 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 19 | use crate::room::RoomCreateWithCreatorEventContent; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 20 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 21 | /// A minimal state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 22 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 23 | /// This type can hold a possibly-redacted state event with an optional |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 24 | /// event ID. The event ID is optional so this type can also hold events from |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 25 | /// invited rooms, where event IDs are not available. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 26 | #[derive(Clone, Debug, Deserialize, Serialize)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 27 | #[serde( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 28 | bound(serialize = "C: Serialize + Clone"), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 29 | from = "MinimalStateEventSerdeHelper<C>", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 30 | into = "MinimalStateEventSerdeHelper<C>" |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 31 | )] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 32 | pub struct MinimalStateEvent<C: PossiblyRedactedStateEventContent + RedactContent> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 33 | /// The event's content. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 34 | pub content: C, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 35 | /// The event's ID, if known. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 36 | pub event_id: Option<OwnedEventId>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 37 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 38 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 39 | impl<C> MinimalStateEvent<C> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 40 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 41 | C: PossiblyRedactedStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 42 | C::Redacted: Into<C>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 43 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 44 | /// Redacts this event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 45 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 46 | /// Does nothing if it is already redacted. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 47 | pub fn redact(&mut self, rules: &RedactionRules) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 48 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 49 | C: Clone, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 50 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 51 | self.content = self.content.clone().redact(rules).into() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 52 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 53 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 54 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 55 | /// Helper type to (de)serialize [`MinimalStateEvent`]. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 56 | #[derive(Serialize, Deserialize)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 57 | enum MinimalStateEventSerdeHelper<C> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 58 | /// Previous variant for a non-redacted event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 59 | Original(MinimalStateEventSerdeHelperInner<C>), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 60 | /// Previous variant for a redacted event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 61 | Redacted(MinimalStateEventSerdeHelperInner<C>), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 62 | /// New variant. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 63 | PossiblyRedacted(MinimalStateEventSerdeHelperInner<C>), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 64 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 65 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 66 | impl<C> From<MinimalStateEventSerdeHelper<C>> for MinimalStateEvent<C> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 67 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 68 | C: PossiblyRedactedStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 69 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 70 | fn from(value: MinimalStateEventSerdeHelper<C>) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 71 | match value { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 72 | MinimalStateEventSerdeHelper::Original(event) => event, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 73 | MinimalStateEventSerdeHelper::Redacted(event) => event, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 74 | MinimalStateEventSerdeHelper::PossiblyRedacted(event) => event, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 75 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 76 | .into() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 77 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 78 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 79 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 80 | impl<C> From<MinimalStateEvent<C>> for MinimalStateEventSerdeHelper<C> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 81 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 82 | C: PossiblyRedactedStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 83 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 84 | fn from(value: MinimalStateEvent<C>) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 85 | Self::PossiblyRedacted(value.into()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 86 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 87 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 88 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 89 | #[derive(Serialize, Deserialize)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 90 | struct MinimalStateEventSerdeHelperInner<C> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 91 | content: C, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 92 | event_id: Option<OwnedEventId>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 93 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 94 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 95 | impl<C> From<MinimalStateEventSerdeHelperInner<C>> for MinimalStateEvent<C> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 96 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 97 | C: PossiblyRedactedStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 98 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 99 | fn from(value: MinimalStateEventSerdeHelperInner<C>) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 100 | let MinimalStateEventSerdeHelperInner { content, event_id } = value; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 101 | Self { content, event_id } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 102 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 103 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 104 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 105 | impl<C> From<MinimalStateEvent<C>> for MinimalStateEventSerdeHelperInner<C> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 106 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 107 | C: PossiblyRedactedStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 108 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 109 | fn from(value: MinimalStateEvent<C>) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 110 | let MinimalStateEvent { content, event_id } = value; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 111 | Self { content, event_id } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 112 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 113 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 114 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 115 | /// A minimal `m.room.member` event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 116 | pub type MinimalRoomMemberEvent = MinimalStateEvent<PossiblyRedactedRoomMemberEventContent>; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 117 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 118 | impl<C1, C2> From<SyncStateEvent<C1>> for MinimalStateEvent<C2> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 119 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 120 | C1: StaticStateEventContent + RedactContent + Into<C2>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 121 | C1::Redacted: RedactedStateEventContent + Into<C2>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 122 | C2: PossiblyRedactedStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 123 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 124 | fn from(ev: SyncStateEvent<C1>) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 125 | match ev { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 126 | SyncStateEvent::Original(ev) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 127 | Self { content: ev.content.into(), event_id: Some(ev.event_id) } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 128 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 129 | SyncStateEvent::Redacted(ev) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 130 | Self { content: ev.content.into(), event_id: Some(ev.event_id) } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 131 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 132 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 133 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 134 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 135 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 136 | impl<C1, C2> From<&SyncStateEvent<C1>> for MinimalStateEvent<C2> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 137 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 138 | C1: Clone + StaticStateEventContent + RedactContent + Into<C2>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 139 | C1::Redacted: Clone + RedactedStateEventContent + Into<C2>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 140 | C2: PossiblyRedactedStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 141 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 142 | fn from(ev: &SyncStateEvent<C1>) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 143 | match ev { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 144 | SyncStateEvent::Original(ev) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 145 | Self { content: ev.content.clone().into(), event_id: Some(ev.event_id.clone()) } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 146 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 147 | SyncStateEvent::Redacted(ev) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 148 | Self { content: ev.content.clone().into(), event_id: Some(ev.event_id.clone()) } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 149 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 150 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 151 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 152 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 153 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 154 | impl From<&SyncRoomCreateEvent> for MinimalStateEvent<RoomCreateWithCreatorEventContent> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 155 | fn from(ev: &SyncRoomCreateEvent) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 156 | match ev { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 157 | SyncStateEvent::Original(ev) => Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 158 | content: RoomCreateWithCreatorEventContent::from_event_content( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 159 | ev.content.clone(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 160 | ev.sender.clone(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 161 | ), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 162 | event_id: Some(ev.event_id.clone()), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 163 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 164 | SyncStateEvent::Redacted(ev) => Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 165 | content: RoomCreateWithCreatorEventContent::from_event_content( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 166 | ev.content.clone(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 167 | ev.sender.clone(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 168 | ), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 169 | event_id: Some(ev.event_id.clone()), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 170 | }, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 171 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 172 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 173 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 174 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 175 | impl<C> From<StrippedStateEvent<C>> for MinimalStateEvent<C> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 176 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 177 | C: PossiblyRedactedStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 178 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 179 | fn from(event: StrippedStateEvent<C>) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 180 | Self { content: event.content, event_id: None } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 181 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 182 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 183 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 184 | impl<C> From<&StrippedStateEvent<C>> for MinimalStateEvent<C> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 185 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 186 | C: Clone + PossiblyRedactedStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 187 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 188 | fn from(event: &StrippedStateEvent<C>) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 189 | Self { content: event.content.clone(), event_id: None } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 190 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 191 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 192 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 193 | impl From<&StrippedRoomCreateEvent> for MinimalStateEvent<RoomCreateWithCreatorEventContent> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 194 | fn from(event: &StrippedRoomCreateEvent) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 195 | let content = RoomCreateWithCreatorEventContent::from_event_content( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 196 | event.content.clone(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 197 | event.sender.clone(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 198 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 199 | Self { content, event_id: None } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 200 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 201 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 202 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 203 | /// A raw state event and its `(type, state_key)` tuple that identifies it |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 204 | /// in the state map of the room. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 205 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 206 | /// This type can also cache the deserialized event lazily when using |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 207 | /// [`RawStateEventWithKeys::deserialize_as()`]. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 208 | #[derive(Debug, Clone)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 209 | pub struct RawStateEventWithKeys<T: AnyStateEventEnum> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 210 | /// The raw state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 211 | pub raw: Raw<T>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 212 | /// The type of the state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 213 | pub event_type: StateEventType, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 214 | /// The state key of the state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 215 | pub state_key: String, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 216 | /// The cached deserialized event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 217 | cached_event: Option<Result<T, ()>>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 218 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 219 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 220 | impl<T: AnyStateEventEnum> RawStateEventWithKeys<T> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 221 | /// Try to construct a `RawStateEventWithKeys` from the given raw state |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 222 | /// event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 223 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 224 | /// Returns `None` if extracting the `type` or `state_key` fails. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 225 | pub fn try_from_raw_state_event(raw: Raw<T>) -> Option<Self> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 226 | let StateEventWithKeysDeHelper { event_type, state_key } = |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 227 | match raw.deserialize_as_unchecked() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 228 | Ok(fields) => fields, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 229 | Err(error) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 230 | warn!(?error, "Couldn't deserialize type and state key of state event"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 231 | return None; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 232 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 233 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 234 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 235 | // It should be a state event, so log if there is no state key. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 236 | let Some(state_key) = state_key else { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 237 | warn!( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 238 | ?event_type, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 239 | "Couldn't deserialize type and state key of state event: missing state key" |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 240 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 241 | return None; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 242 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 243 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 244 | Some(Self { raw, event_type, state_key, cached_event: None }) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 245 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 246 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 247 | /// Try to deserialize the raw event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 248 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 249 | /// The result of the event deserialization is cached for future calls to |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 250 | /// this method. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 251 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 252 | /// Returns `None` if the deserialization failed. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 253 | pub fn deserialize(&mut self) -> Option<&T> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 254 | self.cached_event |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 255 | .get_or_insert_with(|| { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 256 | self.raw.deserialize().map_err(|error| { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 257 | warn!(?error, "Couldn't deserialize state event"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 258 | }) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 259 | }) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 260 | .as_ref() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 261 | .ok() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 262 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 263 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 264 | /// Try to deserialize the raw event and return it as a |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 265 | /// [`MinimalStateEvent`] using the selected variant of |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 266 | /// [`AnyPossiblyRedactedStateEventContent`]. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 267 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 268 | /// This method should only be called if the variant is already known. It is |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 269 | /// considered a developer error for `as_variant_fn` to return `None`, but |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 270 | /// this API was chosen to simplify closures that use the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 271 | /// [`as_variant!`](as_variant::as_variant) macro. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 272 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 273 | /// The result of the event deserialization is cached for future calls to |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 274 | /// this method. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 275 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 276 | /// Returns `None` if the deserialization failed or if `as_variant_fn` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 277 | /// returns `None`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 278 | pub fn deserialize_as_minimal_event<F, C>( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 279 | &mut self, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 280 | as_variant_fn: F, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 281 | ) -> Option<MinimalStateEvent<C>> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 282 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 283 | F: FnOnce(AnyPossiblyRedactedStateEventContent) -> Option<C>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 284 | C: StaticEventContent + PossiblyRedactedStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 285 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 286 | let any_event = self.deserialize()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 287 | let any_content = any_event.get_content(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 288 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 289 | let Some(content) = as_variant_fn(any_content) else { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 290 | // This should be a developer error, or an upstream error. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 291 | error!( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 292 | expected_event_type = ?C::TYPE, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 293 | actual_event_type = ?any_event.get_event_type().to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 294 | "Couldn't deserialize state event content: unexpected type", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 295 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 296 | return None; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 297 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 298 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 299 | Some(MinimalStateEvent { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 300 | content, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 301 | event_id: any_event.get_event_id().map(ToOwned::to_owned), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 302 | }) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 303 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 304 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 305 | /// Override the event cached by |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 306 | /// [`RawStateEventWithKeys::deserialize_as()`]. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 307 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 308 | /// When validating the content of the deserialized event, this can be used |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 309 | /// to edit the parts that fail validation and pass the edited event down |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 310 | /// the chain. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 311 | pub(crate) fn set_cached_event(&mut self, event: T) { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 312 | self.cached_event = Some(Ok(event)); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 313 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 314 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 315 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 316 | impl RawStateEventWithKeys<AnySyncStateEvent> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 317 | /// Try to construct a `RawStateEventWithKeys` from the given raw |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 318 | /// timeline event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 319 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 320 | /// Returns `None` if deserializing the `type` or `state_key` fails, or if |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 321 | /// the event is not a state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 322 | pub fn try_from_raw_timeline_event(raw: &Raw<AnySyncTimelineEvent>) -> Option<Self> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 323 | let StateEventWithKeysDeHelper { event_type, state_key } = match raw |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 324 | .deserialize_as_unchecked() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 325 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 326 | Ok(fields) => fields, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 327 | Err(error) => { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 328 | warn!(?error, "Couldn't deserialize type and optional state key of timeline event"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 329 | return None; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 330 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 331 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 332 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 333 | // If the state key is missing, it is not a state event according to the spec. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 334 | Some(Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 335 | event_type, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 336 | state_key: state_key?, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 337 | raw: raw.clone().cast_unchecked(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 338 | cached_event: None, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 339 | }) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 340 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 341 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 342 | /// Try to deserialize the raw event and return the selected variant of |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 343 | /// [`AnySyncStateEvent`]. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 344 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 345 | /// This method should only be called if the variant is already known. It is |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 346 | /// considered a developer error for `as_variant_fn` to return `None`, but |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 347 | /// this API was chosen to simplify closures that use the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 348 | /// [`as_variant!`](as_variant::as_variant) macro. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 349 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 350 | /// The result of the event deserialization is cached for future calls to |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 351 | /// this method. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 352 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 353 | /// Returns `None` if the deserialization failed or if `as_variant_fn` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 354 | /// returns `None`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 355 | pub fn deserialize_as<F, C>(&mut self, as_variant_fn: F) -> Option<&SyncStateEvent<C>> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 356 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 357 | F: FnOnce(&AnySyncStateEvent) -> Option<&SyncStateEvent<C>>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 358 | C: StaticEventContent + StaticStateEventContent + RedactContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 359 | C::Redacted: RedactedStateEventContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 360 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 361 | let any_event = self.deserialize()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 362 | let event = as_variant_fn(any_event); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 363 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 364 | if event.is_none() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 365 | // This should be a developer error, or an upstream error. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 366 | error!( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 367 | expected_event_type = ?C::TYPE, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 368 | actual_event_type = ?any_event.event_type().to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 369 | "Couldn't deserialize state event: unexpected type", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 370 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 371 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 372 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 373 | event |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 374 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 375 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 376 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 377 | impl RawStateEventWithKeys<AnyStrippedStateEvent> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 378 | /// Try to deserialize the raw event and return the selected variant of |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 379 | /// [`AnyStrippedStateEvent`]. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 380 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 381 | /// This method should only be called if the variant is already known. It is |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 382 | /// considered a developer error for `as_variant_fn` to return `None`, but |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 383 | /// this API was chosen to simplify closures that use the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 384 | /// [`as_variant!`](as_variant::as_variant) macro. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 385 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 386 | /// The result of the event deserialization is cached for future calls to |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 387 | /// this method. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 388 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 389 | /// Returns `None` if the deserialization failed or if `as_variant_fn` |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 390 | /// returns `None`. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 391 | pub fn deserialize_as<F, C>(&mut self, as_variant_fn: F) -> Option<&StrippedStateEvent<C>> |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 392 | where |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 393 | F: FnOnce(&AnyStrippedStateEvent) -> Option<&StrippedStateEvent<C>>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 394 | C: StaticEventContent + PossiblyRedactedStateEventContent, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 395 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 396 | let any_event = self.deserialize()?; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 397 | let event = as_variant_fn(any_event); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 398 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 399 | if event.is_none() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 400 | // This should be a developer error, or an upstream error. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 401 | error!( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 402 | expected_event_type = ?C::TYPE, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 403 | actual_event_type = ?any_event.event_type().to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 404 | "Couldn't deserialize stripped state event: unexpected type", |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 405 | ); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 406 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 407 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 408 | event |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 409 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 410 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 411 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 412 | /// Helper type to deserialize a [`RawStateEventWithKeys`]. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 413 | #[derive(Deserialize)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 414 | struct StateEventWithKeysDeHelper { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 415 | #[serde(rename = "type")] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 416 | event_type: StateEventType, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 417 | /// The state key is optional to be able to differentiate state events from |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 418 | /// other messages in the timeline. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 419 | state_key: Option<String>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 420 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 421 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 422 | /// Helper trait to use common methods of `Any*StateEvent` enums. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 423 | pub trait AnyStateEventEnum: DeserializeOwned { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 424 | /// Get the type of the state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 425 | fn get_event_type(&self) -> StateEventType; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 426 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 427 | /// Get the content of the state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 428 | fn get_content(&self) -> AnyPossiblyRedactedStateEventContent; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 429 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 430 | /// Get the ID of the state event, if any. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 431 | fn get_event_id(&self) -> Option<&EventId>; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 432 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 433 | /// Get the sender of the state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 434 | fn get_sender(&self) -> &UserId; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 435 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 436 | /// Get the timestamp of the state event, if any. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 437 | fn get_origin_server_ts(&self) -> Option<MilliSecondsSinceUnixEpoch>; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 438 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 439 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 440 | impl AnyStateEventEnum for AnySyncStateEvent { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 441 | /// Get the type of the state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 442 | fn get_event_type(&self) -> StateEventType { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 443 | self.event_type() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 444 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 445 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 446 | fn get_content(&self) -> AnyPossiblyRedactedStateEventContent { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 447 | self.content() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 448 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 449 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 450 | fn get_event_id(&self) -> Option<&EventId> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 451 | Some(self.event_id()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 452 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 453 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 454 | fn get_sender(&self) -> &UserId { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 455 | self.sender() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 456 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 457 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 458 | fn get_origin_server_ts(&self) -> Option<MilliSecondsSinceUnixEpoch> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 459 | Some(self.origin_server_ts()) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 460 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 461 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 462 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 463 | impl AnyStateEventEnum for AnyStrippedStateEvent { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 464 | /// Get the type of the state event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 465 | fn get_event_type(&self) -> StateEventType { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 466 | self.event_type() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 467 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 468 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 469 | fn get_content(&self) -> AnyPossiblyRedactedStateEventContent { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 470 | self.content() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 471 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 472 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 473 | fn get_event_id(&self) -> Option<&EventId> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 474 | None |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 475 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 476 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 477 | fn get_sender(&self) -> &UserId { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 478 | self.sender() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 479 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 480 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 481 | fn get_origin_server_ts(&self) -> Option<MilliSecondsSinceUnixEpoch> { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 482 | None |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 483 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 484 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 485 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 486 | #[cfg(test)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 487 | mod tests { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 488 | use ruma::{event_id, events::room::name::PossiblyRedactedRoomNameEventContent}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 489 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 490 | use super::MinimalStateEvent; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 491 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 492 | #[test] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 493 | fn test_backward_compatible_deserialize_minimal_state_event() { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 494 | let event_id = event_id!("$event"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 495 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 496 | // The old format with `Original` and `Redacted` variants works. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 497 | let event = |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 498 | serde_json::from_str::<MinimalStateEvent<PossiblyRedactedRoomNameEventContent>>( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 499 | r#"{"Original":{"content":{"name":"My Room"},"event_id":"$event"}}"#, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 500 | ) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 501 | .unwrap(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 502 | assert_eq!(event.content.name.as_deref(), Some("My Room")); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 503 | assert_eq!(event.event_id.as_deref(), Some(event_id)); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 504 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 505 | let event = |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 506 | serde_json::from_str::<MinimalStateEvent<PossiblyRedactedRoomNameEventContent>>( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 507 | r#"{"Redacted":{"content":{},"event_id":"$event"}}"#, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 508 | ) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 509 | .unwrap(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 510 | assert_eq!(event.content.name, None); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 511 | assert_eq!(event.event_id.as_deref(), Some(event_id)); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 512 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 513 | // The new format works. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 514 | let event = |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 515 | serde_json::from_str::<MinimalStateEvent<PossiblyRedactedRoomNameEventContent>>( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 516 | r#"{"PossiblyRedacted":{"content":{"name":"My Room"},"event_id":"$event"}}"#, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 517 | ) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 518 | .unwrap(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 519 | assert_eq!(event.content.name.as_deref(), Some("My Room")); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 520 | assert_eq!(event.event_id.as_deref(), Some(event_id)); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 521 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 522 | let event = |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 523 | serde_json::from_str::<MinimalStateEvent<PossiblyRedactedRoomNameEventContent>>( |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 524 | r#"{"PossiblyRedacted":{"content":{},"event_id":"$event"}}"#, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 525 | ) |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 526 | .unwrap(); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 527 | assert_eq!(event.content.name, None); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 528 | assert_eq!(event.event_id.as_deref(), Some(event_id)); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 529 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 530 | } |