atagen

matrix-rust-sdk

public
Star0
Watch0
ssh://brewery@pls.lobotomise.me:33/atagen/matrix-rust-sdk.git

Blame: crates/matrix-sdk-base/src/utils.rs

7ff8adafe9e4atagen2026-10-22 12:30 UTC1
use ruma::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC2
    EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, UserId,
7ff8adafe9e4atagen2026-10-22 12:30 UTC3
    events::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC4
        AnyPossiblyRedactedStateEventContent, AnyStrippedStateEvent, AnySyncStateEvent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC5
        AnySyncTimelineEvent, PossiblyRedactedStateEventContent, RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC6
        RedactedStateEventContent, StateEventType, StaticEventContent, StaticStateEventContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC7
        StrippedStateEvent, SyncStateEvent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC8
        room::{
7ff8adafe9e4atagen2026-10-22 12:30 UTC9
            create::{StrippedRoomCreateEvent, SyncRoomCreateEvent},
7ff8adafe9e4atagen2026-10-22 12:30 UTC10
            member::PossiblyRedactedRoomMemberEventContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC11
        },
7ff8adafe9e4atagen2026-10-22 12:30 UTC12
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC13
    room_version_rules::RedactionRules,
7ff8adafe9e4atagen2026-10-22 12:30 UTC14
    serde::Raw,
7ff8adafe9e4atagen2026-10-22 12:30 UTC15
};
7ff8adafe9e4atagen2026-10-22 12:30 UTC16
use serde::{Deserialize, Serialize, de::DeserializeOwned};
7ff8adafe9e4atagen2026-10-22 12:30 UTC17
use tracing::{error, warn};
7ff8adafe9e4atagen2026-10-22 12:30 UTC18
7ff8adafe9e4atagen2026-10-22 12:30 UTC19
use crate::room::RoomCreateWithCreatorEventContent;
7ff8adafe9e4atagen2026-10-22 12:30 UTC20
7ff8adafe9e4atagen2026-10-22 12:30 UTC21
/// A minimal state event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC22
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC23
/// This type can hold a possibly-redacted state event with an optional
7ff8adafe9e4atagen2026-10-22 12:30 UTC24
/// event ID. The event ID is optional so this type can also hold events from
7ff8adafe9e4atagen2026-10-22 12:30 UTC25
/// invited rooms, where event IDs are not available.
7ff8adafe9e4atagen2026-10-22 12:30 UTC26
#[derive(Clone, Debug, Deserialize, Serialize)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC27
#[serde(
7ff8adafe9e4atagen2026-10-22 12:30 UTC28
    bound(serialize = "C: Serialize + Clone"),
7ff8adafe9e4atagen2026-10-22 12:30 UTC29
    from = "MinimalStateEventSerdeHelper<C>",
7ff8adafe9e4atagen2026-10-22 12:30 UTC30
    into = "MinimalStateEventSerdeHelper<C>"
7ff8adafe9e4atagen2026-10-22 12:30 UTC31
)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC32
pub struct MinimalStateEvent<C: PossiblyRedactedStateEventContent + RedactContent> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC33
    /// The event's content.
7ff8adafe9e4atagen2026-10-22 12:30 UTC34
    pub content: C,
7ff8adafe9e4atagen2026-10-22 12:30 UTC35
    /// The event's ID, if known.
7ff8adafe9e4atagen2026-10-22 12:30 UTC36
    pub event_id: Option<OwnedEventId>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC37
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC38
7ff8adafe9e4atagen2026-10-22 12:30 UTC39
impl<C> MinimalStateEvent<C>
7ff8adafe9e4atagen2026-10-22 12:30 UTC40
where
7ff8adafe9e4atagen2026-10-22 12:30 UTC41
    C: PossiblyRedactedStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC42
    C::Redacted: Into<C>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC43
{
7ff8adafe9e4atagen2026-10-22 12:30 UTC44
    /// Redacts this event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC45
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC46
    /// Does nothing if it is already redacted.
7ff8adafe9e4atagen2026-10-22 12:30 UTC47
    pub fn redact(&mut self, rules: &RedactionRules)
7ff8adafe9e4atagen2026-10-22 12:30 UTC48
    where
7ff8adafe9e4atagen2026-10-22 12:30 UTC49
        C: Clone,
7ff8adafe9e4atagen2026-10-22 12:30 UTC50
    {
7ff8adafe9e4atagen2026-10-22 12:30 UTC51
        self.content = self.content.clone().redact(rules).into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC52
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC53
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC54
7ff8adafe9e4atagen2026-10-22 12:30 UTC55
/// Helper type to (de)serialize [`MinimalStateEvent`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC56
#[derive(Serialize, Deserialize)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC57
enum MinimalStateEventSerdeHelper<C> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC58
    /// Previous variant for a non-redacted event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC59
    Original(MinimalStateEventSerdeHelperInner<C>),
7ff8adafe9e4atagen2026-10-22 12:30 UTC60
    /// Previous variant for a redacted event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC61
    Redacted(MinimalStateEventSerdeHelperInner<C>),
7ff8adafe9e4atagen2026-10-22 12:30 UTC62
    /// New variant.
7ff8adafe9e4atagen2026-10-22 12:30 UTC63
    PossiblyRedacted(MinimalStateEventSerdeHelperInner<C>),
7ff8adafe9e4atagen2026-10-22 12:30 UTC64
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC65
7ff8adafe9e4atagen2026-10-22 12:30 UTC66
impl<C> From<MinimalStateEventSerdeHelper<C>> for MinimalStateEvent<C>
7ff8adafe9e4atagen2026-10-22 12:30 UTC67
where
7ff8adafe9e4atagen2026-10-22 12:30 UTC68
    C: PossiblyRedactedStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC69
{
7ff8adafe9e4atagen2026-10-22 12:30 UTC70
    fn from(value: MinimalStateEventSerdeHelper<C>) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC71
        match value {
7ff8adafe9e4atagen2026-10-22 12:30 UTC72
            MinimalStateEventSerdeHelper::Original(event) => event,
7ff8adafe9e4atagen2026-10-22 12:30 UTC73
            MinimalStateEventSerdeHelper::Redacted(event) => event,
7ff8adafe9e4atagen2026-10-22 12:30 UTC74
            MinimalStateEventSerdeHelper::PossiblyRedacted(event) => event,
7ff8adafe9e4atagen2026-10-22 12:30 UTC75
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC76
        .into()
7ff8adafe9e4atagen2026-10-22 12:30 UTC77
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC78
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC79
7ff8adafe9e4atagen2026-10-22 12:30 UTC80
impl<C> From<MinimalStateEvent<C>> for MinimalStateEventSerdeHelper<C>
7ff8adafe9e4atagen2026-10-22 12:30 UTC81
where
7ff8adafe9e4atagen2026-10-22 12:30 UTC82
    C: PossiblyRedactedStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC83
{
7ff8adafe9e4atagen2026-10-22 12:30 UTC84
    fn from(value: MinimalStateEvent<C>) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC85
        Self::PossiblyRedacted(value.into())
7ff8adafe9e4atagen2026-10-22 12:30 UTC86
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC87
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC88
7ff8adafe9e4atagen2026-10-22 12:30 UTC89
#[derive(Serialize, Deserialize)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC90
struct MinimalStateEventSerdeHelperInner<C> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC91
    content: C,
7ff8adafe9e4atagen2026-10-22 12:30 UTC92
    event_id: Option<OwnedEventId>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC93
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC94
7ff8adafe9e4atagen2026-10-22 12:30 UTC95
impl<C> From<MinimalStateEventSerdeHelperInner<C>> for MinimalStateEvent<C>
7ff8adafe9e4atagen2026-10-22 12:30 UTC96
where
7ff8adafe9e4atagen2026-10-22 12:30 UTC97
    C: PossiblyRedactedStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC98
{
7ff8adafe9e4atagen2026-10-22 12:30 UTC99
    fn from(value: MinimalStateEventSerdeHelperInner<C>) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC100
        let MinimalStateEventSerdeHelperInner { content, event_id } = value;
7ff8adafe9e4atagen2026-10-22 12:30 UTC101
        Self { content, event_id }
7ff8adafe9e4atagen2026-10-22 12:30 UTC102
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC103
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC104
7ff8adafe9e4atagen2026-10-22 12:30 UTC105
impl<C> From<MinimalStateEvent<C>> for MinimalStateEventSerdeHelperInner<C>
7ff8adafe9e4atagen2026-10-22 12:30 UTC106
where
7ff8adafe9e4atagen2026-10-22 12:30 UTC107
    C: PossiblyRedactedStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC108
{
7ff8adafe9e4atagen2026-10-22 12:30 UTC109
    fn from(value: MinimalStateEvent<C>) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC110
        let MinimalStateEvent { content, event_id } = value;
7ff8adafe9e4atagen2026-10-22 12:30 UTC111
        Self { content, event_id }
7ff8adafe9e4atagen2026-10-22 12:30 UTC112
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC113
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC114
7ff8adafe9e4atagen2026-10-22 12:30 UTC115
/// A minimal `m.room.member` event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC116
pub type MinimalRoomMemberEvent = MinimalStateEvent<PossiblyRedactedRoomMemberEventContent>;
7ff8adafe9e4atagen2026-10-22 12:30 UTC117
7ff8adafe9e4atagen2026-10-22 12:30 UTC118
impl<C1, C2> From<SyncStateEvent<C1>> for MinimalStateEvent<C2>
7ff8adafe9e4atagen2026-10-22 12:30 UTC119
where
7ff8adafe9e4atagen2026-10-22 12:30 UTC120
    C1: StaticStateEventContent + RedactContent + Into<C2>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC121
    C1::Redacted: RedactedStateEventContent + Into<C2>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC122
    C2: PossiblyRedactedStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC123
{
7ff8adafe9e4atagen2026-10-22 12:30 UTC124
    fn from(ev: SyncStateEvent<C1>) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC125
        match ev {
7ff8adafe9e4atagen2026-10-22 12:30 UTC126
            SyncStateEvent::Original(ev) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC127
                Self { content: ev.content.into(), event_id: Some(ev.event_id) }
7ff8adafe9e4atagen2026-10-22 12:30 UTC128
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC129
            SyncStateEvent::Redacted(ev) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC130
                Self { content: ev.content.into(), event_id: Some(ev.event_id) }
7ff8adafe9e4atagen2026-10-22 12:30 UTC131
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC132
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC133
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC134
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC135
7ff8adafe9e4atagen2026-10-22 12:30 UTC136
impl<C1, C2> From<&SyncStateEvent<C1>> for MinimalStateEvent<C2>
7ff8adafe9e4atagen2026-10-22 12:30 UTC137
where
7ff8adafe9e4atagen2026-10-22 12:30 UTC138
    C1: Clone + StaticStateEventContent + RedactContent + Into<C2>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC139
    C1::Redacted: Clone + RedactedStateEventContent + Into<C2>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC140
    C2: PossiblyRedactedStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC141
{
7ff8adafe9e4atagen2026-10-22 12:30 UTC142
    fn from(ev: &SyncStateEvent<C1>) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC143
        match ev {
7ff8adafe9e4atagen2026-10-22 12:30 UTC144
            SyncStateEvent::Original(ev) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC145
                Self { content: ev.content.clone().into(), event_id: Some(ev.event_id.clone()) }
7ff8adafe9e4atagen2026-10-22 12:30 UTC146
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC147
            SyncStateEvent::Redacted(ev) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC148
                Self { content: ev.content.clone().into(), event_id: Some(ev.event_id.clone()) }
7ff8adafe9e4atagen2026-10-22 12:30 UTC149
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC150
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC151
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC152
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC153
7ff8adafe9e4atagen2026-10-22 12:30 UTC154
impl From<&SyncRoomCreateEvent> for MinimalStateEvent<RoomCreateWithCreatorEventContent> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC155
    fn from(ev: &SyncRoomCreateEvent) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC156
        match ev {
7ff8adafe9e4atagen2026-10-22 12:30 UTC157
            SyncStateEvent::Original(ev) => Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC158
                content: RoomCreateWithCreatorEventContent::from_event_content(
7ff8adafe9e4atagen2026-10-22 12:30 UTC159
                    ev.content.clone(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC160
                    ev.sender.clone(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC161
                ),
7ff8adafe9e4atagen2026-10-22 12:30 UTC162
                event_id: Some(ev.event_id.clone()),
7ff8adafe9e4atagen2026-10-22 12:30 UTC163
            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC164
            SyncStateEvent::Redacted(ev) => Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC165
                content: RoomCreateWithCreatorEventContent::from_event_content(
7ff8adafe9e4atagen2026-10-22 12:30 UTC166
                    ev.content.clone(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC167
                    ev.sender.clone(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC168
                ),
7ff8adafe9e4atagen2026-10-22 12:30 UTC169
                event_id: Some(ev.event_id.clone()),
7ff8adafe9e4atagen2026-10-22 12:30 UTC170
            },
7ff8adafe9e4atagen2026-10-22 12:30 UTC171
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC172
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC173
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC174
7ff8adafe9e4atagen2026-10-22 12:30 UTC175
impl<C> From<StrippedStateEvent<C>> for MinimalStateEvent<C>
7ff8adafe9e4atagen2026-10-22 12:30 UTC176
where
7ff8adafe9e4atagen2026-10-22 12:30 UTC177
    C: PossiblyRedactedStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC178
{
7ff8adafe9e4atagen2026-10-22 12:30 UTC179
    fn from(event: StrippedStateEvent<C>) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC180
        Self { content: event.content, event_id: None }
7ff8adafe9e4atagen2026-10-22 12:30 UTC181
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC182
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC183
7ff8adafe9e4atagen2026-10-22 12:30 UTC184
impl<C> From<&StrippedStateEvent<C>> for MinimalStateEvent<C>
7ff8adafe9e4atagen2026-10-22 12:30 UTC185
where
7ff8adafe9e4atagen2026-10-22 12:30 UTC186
    C: Clone + PossiblyRedactedStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC187
{
7ff8adafe9e4atagen2026-10-22 12:30 UTC188
    fn from(event: &StrippedStateEvent<C>) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC189
        Self { content: event.content.clone(), event_id: None }
7ff8adafe9e4atagen2026-10-22 12:30 UTC190
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC191
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC192
7ff8adafe9e4atagen2026-10-22 12:30 UTC193
impl From<&StrippedRoomCreateEvent> for MinimalStateEvent<RoomCreateWithCreatorEventContent> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC194
    fn from(event: &StrippedRoomCreateEvent) -> Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC195
        let content = RoomCreateWithCreatorEventContent::from_event_content(
7ff8adafe9e4atagen2026-10-22 12:30 UTC196
            event.content.clone(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC197
            event.sender.clone(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC198
        );
7ff8adafe9e4atagen2026-10-22 12:30 UTC199
        Self { content, event_id: None }
7ff8adafe9e4atagen2026-10-22 12:30 UTC200
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC201
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC202
7ff8adafe9e4atagen2026-10-22 12:30 UTC203
/// A raw state event and its `(type, state_key)` tuple that identifies it
7ff8adafe9e4atagen2026-10-22 12:30 UTC204
/// in the state map of the room.
7ff8adafe9e4atagen2026-10-22 12:30 UTC205
///
7ff8adafe9e4atagen2026-10-22 12:30 UTC206
/// This type can also cache the deserialized event lazily when using
7ff8adafe9e4atagen2026-10-22 12:30 UTC207
/// [`RawStateEventWithKeys::deserialize_as()`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC208
#[derive(Debug, Clone)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC209
pub struct RawStateEventWithKeys<T: AnyStateEventEnum> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC210
    /// The raw state event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC211
    pub raw: Raw<T>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC212
    /// The type of the state event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC213
    pub event_type: StateEventType,
7ff8adafe9e4atagen2026-10-22 12:30 UTC214
    /// The state key of the state event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC215
    pub state_key: String,
7ff8adafe9e4atagen2026-10-22 12:30 UTC216
    /// The cached deserialized event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC217
    cached_event: Option<Result<T, ()>>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC218
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC219
7ff8adafe9e4atagen2026-10-22 12:30 UTC220
impl<T: AnyStateEventEnum> RawStateEventWithKeys<T> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC221
    /// Try to construct a `RawStateEventWithKeys` from the given raw state
7ff8adafe9e4atagen2026-10-22 12:30 UTC222
    /// event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC223
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC224
    /// Returns `None` if extracting the `type` or `state_key` fails.
7ff8adafe9e4atagen2026-10-22 12:30 UTC225
    pub fn try_from_raw_state_event(raw: Raw<T>) -> Option<Self> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC226
        let StateEventWithKeysDeHelper { event_type, state_key } =
7ff8adafe9e4atagen2026-10-22 12:30 UTC227
            match raw.deserialize_as_unchecked() {
7ff8adafe9e4atagen2026-10-22 12:30 UTC228
                Ok(fields) => fields,
7ff8adafe9e4atagen2026-10-22 12:30 UTC229
                Err(error) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC230
                    warn!(?error, "Couldn't deserialize type and state key of state event");
7ff8adafe9e4atagen2026-10-22 12:30 UTC231
                    return None;
7ff8adafe9e4atagen2026-10-22 12:30 UTC232
                }
7ff8adafe9e4atagen2026-10-22 12:30 UTC233
            };
7ff8adafe9e4atagen2026-10-22 12:30 UTC234
7ff8adafe9e4atagen2026-10-22 12:30 UTC235
        // It should be a state event, so log if there is no state key.
7ff8adafe9e4atagen2026-10-22 12:30 UTC236
        let Some(state_key) = state_key else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC237
            warn!(
7ff8adafe9e4atagen2026-10-22 12:30 UTC238
                ?event_type,
7ff8adafe9e4atagen2026-10-22 12:30 UTC239
                "Couldn't deserialize type and state key of state event: missing state key"
7ff8adafe9e4atagen2026-10-22 12:30 UTC240
            );
7ff8adafe9e4atagen2026-10-22 12:30 UTC241
            return None;
7ff8adafe9e4atagen2026-10-22 12:30 UTC242
        };
7ff8adafe9e4atagen2026-10-22 12:30 UTC243
7ff8adafe9e4atagen2026-10-22 12:30 UTC244
        Some(Self { raw, event_type, state_key, cached_event: None })
7ff8adafe9e4atagen2026-10-22 12:30 UTC245
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC246
7ff8adafe9e4atagen2026-10-22 12:30 UTC247
    /// Try to deserialize the raw event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC248
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC249
    /// The result of the event deserialization is cached for future calls to
7ff8adafe9e4atagen2026-10-22 12:30 UTC250
    /// this method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC251
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC252
    /// Returns `None` if the deserialization failed.
7ff8adafe9e4atagen2026-10-22 12:30 UTC253
    pub fn deserialize(&mut self) -> Option<&T> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC254
        self.cached_event
7ff8adafe9e4atagen2026-10-22 12:30 UTC255
            .get_or_insert_with(|| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC256
                self.raw.deserialize().map_err(|error| {
7ff8adafe9e4atagen2026-10-22 12:30 UTC257
                    warn!(?error, "Couldn't deserialize state event");
7ff8adafe9e4atagen2026-10-22 12:30 UTC258
                })
7ff8adafe9e4atagen2026-10-22 12:30 UTC259
            })
7ff8adafe9e4atagen2026-10-22 12:30 UTC260
            .as_ref()
7ff8adafe9e4atagen2026-10-22 12:30 UTC261
            .ok()
7ff8adafe9e4atagen2026-10-22 12:30 UTC262
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC263
7ff8adafe9e4atagen2026-10-22 12:30 UTC264
    /// Try to deserialize the raw event and return it as a
7ff8adafe9e4atagen2026-10-22 12:30 UTC265
    /// [`MinimalStateEvent`] using the selected variant of
7ff8adafe9e4atagen2026-10-22 12:30 UTC266
    /// [`AnyPossiblyRedactedStateEventContent`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC267
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC268
    /// This method should only be called if the variant is already known. It is
7ff8adafe9e4atagen2026-10-22 12:30 UTC269
    /// considered a developer error for `as_variant_fn` to return `None`, but
7ff8adafe9e4atagen2026-10-22 12:30 UTC270
    /// this API was chosen to simplify closures that use the
7ff8adafe9e4atagen2026-10-22 12:30 UTC271
    /// [`as_variant!`](as_variant::as_variant) macro.
7ff8adafe9e4atagen2026-10-22 12:30 UTC272
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC273
    /// The result of the event deserialization is cached for future calls to
7ff8adafe9e4atagen2026-10-22 12:30 UTC274
    /// this method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC275
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC276
    /// Returns `None` if the deserialization failed or if `as_variant_fn`
7ff8adafe9e4atagen2026-10-22 12:30 UTC277
    /// returns `None`.
7ff8adafe9e4atagen2026-10-22 12:30 UTC278
    pub fn deserialize_as_minimal_event<F, C>(
7ff8adafe9e4atagen2026-10-22 12:30 UTC279
        &mut self,
7ff8adafe9e4atagen2026-10-22 12:30 UTC280
        as_variant_fn: F,
7ff8adafe9e4atagen2026-10-22 12:30 UTC281
    ) -> Option<MinimalStateEvent<C>>
7ff8adafe9e4atagen2026-10-22 12:30 UTC282
    where
7ff8adafe9e4atagen2026-10-22 12:30 UTC283
        F: FnOnce(AnyPossiblyRedactedStateEventContent) -> Option<C>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC284
        C: StaticEventContent + PossiblyRedactedStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC285
    {
7ff8adafe9e4atagen2026-10-22 12:30 UTC286
        let any_event = self.deserialize()?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC287
        let any_content = any_event.get_content();
7ff8adafe9e4atagen2026-10-22 12:30 UTC288
7ff8adafe9e4atagen2026-10-22 12:30 UTC289
        let Some(content) = as_variant_fn(any_content) else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC290
            // This should be a developer error, or an upstream error.
7ff8adafe9e4atagen2026-10-22 12:30 UTC291
            error!(
7ff8adafe9e4atagen2026-10-22 12:30 UTC292
                expected_event_type = ?C::TYPE,
7ff8adafe9e4atagen2026-10-22 12:30 UTC293
                actual_event_type = ?any_event.get_event_type().to_string(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC294
                "Couldn't deserialize state event content: unexpected type",
7ff8adafe9e4atagen2026-10-22 12:30 UTC295
            );
7ff8adafe9e4atagen2026-10-22 12:30 UTC296
            return None;
7ff8adafe9e4atagen2026-10-22 12:30 UTC297
        };
7ff8adafe9e4atagen2026-10-22 12:30 UTC298
7ff8adafe9e4atagen2026-10-22 12:30 UTC299
        Some(MinimalStateEvent {
7ff8adafe9e4atagen2026-10-22 12:30 UTC300
            content,
7ff8adafe9e4atagen2026-10-22 12:30 UTC301
            event_id: any_event.get_event_id().map(ToOwned::to_owned),
7ff8adafe9e4atagen2026-10-22 12:30 UTC302
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC303
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC304
7ff8adafe9e4atagen2026-10-22 12:30 UTC305
    /// Override the event cached by
7ff8adafe9e4atagen2026-10-22 12:30 UTC306
    /// [`RawStateEventWithKeys::deserialize_as()`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC307
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC308
    /// When validating the content of the deserialized event, this can be used
7ff8adafe9e4atagen2026-10-22 12:30 UTC309
    /// to edit the parts that fail validation and pass the edited event down
7ff8adafe9e4atagen2026-10-22 12:30 UTC310
    /// the chain.
7ff8adafe9e4atagen2026-10-22 12:30 UTC311
    pub(crate) fn set_cached_event(&mut self, event: T) {
7ff8adafe9e4atagen2026-10-22 12:30 UTC312
        self.cached_event = Some(Ok(event));
7ff8adafe9e4atagen2026-10-22 12:30 UTC313
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC314
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC315
7ff8adafe9e4atagen2026-10-22 12:30 UTC316
impl RawStateEventWithKeys<AnySyncStateEvent> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC317
    /// Try to construct a `RawStateEventWithKeys` from the given raw
7ff8adafe9e4atagen2026-10-22 12:30 UTC318
    /// timeline event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC319
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC320
    /// Returns `None` if deserializing the `type` or `state_key` fails, or if
7ff8adafe9e4atagen2026-10-22 12:30 UTC321
    /// the event is not a state event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC322
    pub fn try_from_raw_timeline_event(raw: &Raw<AnySyncTimelineEvent>) -> Option<Self> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC323
        let StateEventWithKeysDeHelper { event_type, state_key } = match raw
7ff8adafe9e4atagen2026-10-22 12:30 UTC324
            .deserialize_as_unchecked()
7ff8adafe9e4atagen2026-10-22 12:30 UTC325
        {
7ff8adafe9e4atagen2026-10-22 12:30 UTC326
            Ok(fields) => fields,
7ff8adafe9e4atagen2026-10-22 12:30 UTC327
            Err(error) => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC328
                warn!(?error, "Couldn't deserialize type and optional state key of timeline event");
7ff8adafe9e4atagen2026-10-22 12:30 UTC329
                return None;
7ff8adafe9e4atagen2026-10-22 12:30 UTC330
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC331
        };
7ff8adafe9e4atagen2026-10-22 12:30 UTC332
7ff8adafe9e4atagen2026-10-22 12:30 UTC333
        // If the state key is missing, it is not a state event according to the spec.
7ff8adafe9e4atagen2026-10-22 12:30 UTC334
        Some(Self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC335
            event_type,
7ff8adafe9e4atagen2026-10-22 12:30 UTC336
            state_key: state_key?,
7ff8adafe9e4atagen2026-10-22 12:30 UTC337
            raw: raw.clone().cast_unchecked(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC338
            cached_event: None,
7ff8adafe9e4atagen2026-10-22 12:30 UTC339
        })
7ff8adafe9e4atagen2026-10-22 12:30 UTC340
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC341
7ff8adafe9e4atagen2026-10-22 12:30 UTC342
    /// Try to deserialize the raw event and return the selected variant of
7ff8adafe9e4atagen2026-10-22 12:30 UTC343
    /// [`AnySyncStateEvent`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC344
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC345
    /// This method should only be called if the variant is already known. It is
7ff8adafe9e4atagen2026-10-22 12:30 UTC346
    /// considered a developer error for `as_variant_fn` to return `None`, but
7ff8adafe9e4atagen2026-10-22 12:30 UTC347
    /// this API was chosen to simplify closures that use the
7ff8adafe9e4atagen2026-10-22 12:30 UTC348
    /// [`as_variant!`](as_variant::as_variant) macro.
7ff8adafe9e4atagen2026-10-22 12:30 UTC349
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC350
    /// The result of the event deserialization is cached for future calls to
7ff8adafe9e4atagen2026-10-22 12:30 UTC351
    /// this method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC352
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC353
    /// Returns `None` if the deserialization failed or if `as_variant_fn`
7ff8adafe9e4atagen2026-10-22 12:30 UTC354
    /// returns `None`.
7ff8adafe9e4atagen2026-10-22 12:30 UTC355
    pub fn deserialize_as<F, C>(&mut self, as_variant_fn: F) -> Option<&SyncStateEvent<C>>
7ff8adafe9e4atagen2026-10-22 12:30 UTC356
    where
7ff8adafe9e4atagen2026-10-22 12:30 UTC357
        F: FnOnce(&AnySyncStateEvent) -> Option<&SyncStateEvent<C>>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC358
        C: StaticEventContent + StaticStateEventContent + RedactContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC359
        C::Redacted: RedactedStateEventContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC360
    {
7ff8adafe9e4atagen2026-10-22 12:30 UTC361
        let any_event = self.deserialize()?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC362
        let event = as_variant_fn(any_event);
7ff8adafe9e4atagen2026-10-22 12:30 UTC363
7ff8adafe9e4atagen2026-10-22 12:30 UTC364
        if event.is_none() {
7ff8adafe9e4atagen2026-10-22 12:30 UTC365
            // This should be a developer error, or an upstream error.
7ff8adafe9e4atagen2026-10-22 12:30 UTC366
            error!(
7ff8adafe9e4atagen2026-10-22 12:30 UTC367
                expected_event_type = ?C::TYPE,
7ff8adafe9e4atagen2026-10-22 12:30 UTC368
                actual_event_type = ?any_event.event_type().to_string(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC369
                "Couldn't deserialize state event: unexpected type",
7ff8adafe9e4atagen2026-10-22 12:30 UTC370
            );
7ff8adafe9e4atagen2026-10-22 12:30 UTC371
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC372
7ff8adafe9e4atagen2026-10-22 12:30 UTC373
        event
7ff8adafe9e4atagen2026-10-22 12:30 UTC374
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC375
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC376
7ff8adafe9e4atagen2026-10-22 12:30 UTC377
impl RawStateEventWithKeys<AnyStrippedStateEvent> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC378
    /// Try to deserialize the raw event and return the selected variant of
7ff8adafe9e4atagen2026-10-22 12:30 UTC379
    /// [`AnyStrippedStateEvent`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC380
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC381
    /// This method should only be called if the variant is already known. It is
7ff8adafe9e4atagen2026-10-22 12:30 UTC382
    /// considered a developer error for `as_variant_fn` to return `None`, but
7ff8adafe9e4atagen2026-10-22 12:30 UTC383
    /// this API was chosen to simplify closures that use the
7ff8adafe9e4atagen2026-10-22 12:30 UTC384
    /// [`as_variant!`](as_variant::as_variant) macro.
7ff8adafe9e4atagen2026-10-22 12:30 UTC385
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC386
    /// The result of the event deserialization is cached for future calls to
7ff8adafe9e4atagen2026-10-22 12:30 UTC387
    /// this method.
7ff8adafe9e4atagen2026-10-22 12:30 UTC388
    ///
7ff8adafe9e4atagen2026-10-22 12:30 UTC389
    /// Returns `None` if the deserialization failed or if `as_variant_fn`
7ff8adafe9e4atagen2026-10-22 12:30 UTC390
    /// returns `None`.
7ff8adafe9e4atagen2026-10-22 12:30 UTC391
    pub fn deserialize_as<F, C>(&mut self, as_variant_fn: F) -> Option<&StrippedStateEvent<C>>
7ff8adafe9e4atagen2026-10-22 12:30 UTC392
    where
7ff8adafe9e4atagen2026-10-22 12:30 UTC393
        F: FnOnce(&AnyStrippedStateEvent) -> Option<&StrippedStateEvent<C>>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC394
        C: StaticEventContent + PossiblyRedactedStateEventContent,
7ff8adafe9e4atagen2026-10-22 12:30 UTC395
    {
7ff8adafe9e4atagen2026-10-22 12:30 UTC396
        let any_event = self.deserialize()?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC397
        let event = as_variant_fn(any_event);
7ff8adafe9e4atagen2026-10-22 12:30 UTC398
7ff8adafe9e4atagen2026-10-22 12:30 UTC399
        if event.is_none() {
7ff8adafe9e4atagen2026-10-22 12:30 UTC400
            // This should be a developer error, or an upstream error.
7ff8adafe9e4atagen2026-10-22 12:30 UTC401
            error!(
7ff8adafe9e4atagen2026-10-22 12:30 UTC402
                expected_event_type = ?C::TYPE,
7ff8adafe9e4atagen2026-10-22 12:30 UTC403
                actual_event_type = ?any_event.event_type().to_string(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC404
                "Couldn't deserialize stripped state event: unexpected type",
7ff8adafe9e4atagen2026-10-22 12:30 UTC405
            );
7ff8adafe9e4atagen2026-10-22 12:30 UTC406
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC407
7ff8adafe9e4atagen2026-10-22 12:30 UTC408
        event
7ff8adafe9e4atagen2026-10-22 12:30 UTC409
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC410
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC411
7ff8adafe9e4atagen2026-10-22 12:30 UTC412
/// Helper type to deserialize a [`RawStateEventWithKeys`].
7ff8adafe9e4atagen2026-10-22 12:30 UTC413
#[derive(Deserialize)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC414
struct StateEventWithKeysDeHelper {
7ff8adafe9e4atagen2026-10-22 12:30 UTC415
    #[serde(rename = "type")]
7ff8adafe9e4atagen2026-10-22 12:30 UTC416
    event_type: StateEventType,
7ff8adafe9e4atagen2026-10-22 12:30 UTC417
    /// The state key is optional to be able to differentiate state events from
7ff8adafe9e4atagen2026-10-22 12:30 UTC418
    /// other messages in the timeline.
7ff8adafe9e4atagen2026-10-22 12:30 UTC419
    state_key: Option<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC420
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC421
7ff8adafe9e4atagen2026-10-22 12:30 UTC422
/// Helper trait to use common methods of `Any*StateEvent` enums.
7ff8adafe9e4atagen2026-10-22 12:30 UTC423
pub trait AnyStateEventEnum: DeserializeOwned {
7ff8adafe9e4atagen2026-10-22 12:30 UTC424
    /// Get the type of the state event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC425
    fn get_event_type(&self) -> StateEventType;
7ff8adafe9e4atagen2026-10-22 12:30 UTC426
7ff8adafe9e4atagen2026-10-22 12:30 UTC427
    /// Get the content of the state event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC428
    fn get_content(&self) -> AnyPossiblyRedactedStateEventContent;
7ff8adafe9e4atagen2026-10-22 12:30 UTC429
7ff8adafe9e4atagen2026-10-22 12:30 UTC430
    /// Get the ID of the state event, if any.
7ff8adafe9e4atagen2026-10-22 12:30 UTC431
    fn get_event_id(&self) -> Option<&EventId>;
7ff8adafe9e4atagen2026-10-22 12:30 UTC432
7ff8adafe9e4atagen2026-10-22 12:30 UTC433
    /// Get the sender of the state event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC434
    fn get_sender(&self) -> &UserId;
7ff8adafe9e4atagen2026-10-22 12:30 UTC435
7ff8adafe9e4atagen2026-10-22 12:30 UTC436
    /// Get the timestamp of the state event, if any.
7ff8adafe9e4atagen2026-10-22 12:30 UTC437
    fn get_origin_server_ts(&self) -> Option<MilliSecondsSinceUnixEpoch>;
7ff8adafe9e4atagen2026-10-22 12:30 UTC438
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC439
7ff8adafe9e4atagen2026-10-22 12:30 UTC440
impl AnyStateEventEnum for AnySyncStateEvent {
7ff8adafe9e4atagen2026-10-22 12:30 UTC441
    /// Get the type of the state event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC442
    fn get_event_type(&self) -> StateEventType {
7ff8adafe9e4atagen2026-10-22 12:30 UTC443
        self.event_type()
7ff8adafe9e4atagen2026-10-22 12:30 UTC444
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC445
7ff8adafe9e4atagen2026-10-22 12:30 UTC446
    fn get_content(&self) -> AnyPossiblyRedactedStateEventContent {
7ff8adafe9e4atagen2026-10-22 12:30 UTC447
        self.content()
7ff8adafe9e4atagen2026-10-22 12:30 UTC448
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC449
7ff8adafe9e4atagen2026-10-22 12:30 UTC450
    fn get_event_id(&self) -> Option<&EventId> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC451
        Some(self.event_id())
7ff8adafe9e4atagen2026-10-22 12:30 UTC452
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC453
7ff8adafe9e4atagen2026-10-22 12:30 UTC454
    fn get_sender(&self) -> &UserId {
7ff8adafe9e4atagen2026-10-22 12:30 UTC455
        self.sender()
7ff8adafe9e4atagen2026-10-22 12:30 UTC456
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC457
7ff8adafe9e4atagen2026-10-22 12:30 UTC458
    fn get_origin_server_ts(&self) -> Option<MilliSecondsSinceUnixEpoch> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC459
        Some(self.origin_server_ts())
7ff8adafe9e4atagen2026-10-22 12:30 UTC460
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC461
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC462
7ff8adafe9e4atagen2026-10-22 12:30 UTC463
impl AnyStateEventEnum for AnyStrippedStateEvent {
7ff8adafe9e4atagen2026-10-22 12:30 UTC464
    /// Get the type of the state event.
7ff8adafe9e4atagen2026-10-22 12:30 UTC465
    fn get_event_type(&self) -> StateEventType {
7ff8adafe9e4atagen2026-10-22 12:30 UTC466
        self.event_type()
7ff8adafe9e4atagen2026-10-22 12:30 UTC467
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC468
7ff8adafe9e4atagen2026-10-22 12:30 UTC469
    fn get_content(&self) -> AnyPossiblyRedactedStateEventContent {
7ff8adafe9e4atagen2026-10-22 12:30 UTC470
        self.content()
7ff8adafe9e4atagen2026-10-22 12:30 UTC471
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC472
7ff8adafe9e4atagen2026-10-22 12:30 UTC473
    fn get_event_id(&self) -> Option<&EventId> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC474
        None
7ff8adafe9e4atagen2026-10-22 12:30 UTC475
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC476
7ff8adafe9e4atagen2026-10-22 12:30 UTC477
    fn get_sender(&self) -> &UserId {
7ff8adafe9e4atagen2026-10-22 12:30 UTC478
        self.sender()
7ff8adafe9e4atagen2026-10-22 12:30 UTC479
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC480
7ff8adafe9e4atagen2026-10-22 12:30 UTC481
    fn get_origin_server_ts(&self) -> Option<MilliSecondsSinceUnixEpoch> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC482
        None
7ff8adafe9e4atagen2026-10-22 12:30 UTC483
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC484
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC485
7ff8adafe9e4atagen2026-10-22 12:30 UTC486
#[cfg(test)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC487
mod tests {
7ff8adafe9e4atagen2026-10-22 12:30 UTC488
    use ruma::{event_id, events::room::name::PossiblyRedactedRoomNameEventContent};
7ff8adafe9e4atagen2026-10-22 12:30 UTC489
7ff8adafe9e4atagen2026-10-22 12:30 UTC490
    use super::MinimalStateEvent;
7ff8adafe9e4atagen2026-10-22 12:30 UTC491
7ff8adafe9e4atagen2026-10-22 12:30 UTC492
    #[test]
7ff8adafe9e4atagen2026-10-22 12:30 UTC493
    fn test_backward_compatible_deserialize_minimal_state_event() {
7ff8adafe9e4atagen2026-10-22 12:30 UTC494
        let event_id = event_id!("$event");
7ff8adafe9e4atagen2026-10-22 12:30 UTC495
7ff8adafe9e4atagen2026-10-22 12:30 UTC496
        // The old format with `Original` and `Redacted` variants works.
7ff8adafe9e4atagen2026-10-22 12:30 UTC497
        let event =
7ff8adafe9e4atagen2026-10-22 12:30 UTC498
            serde_json::from_str::<MinimalStateEvent<PossiblyRedactedRoomNameEventContent>>(
7ff8adafe9e4atagen2026-10-22 12:30 UTC499
                r#"{"Original":{"content":{"name":"My Room"},"event_id":"$event"}}"#,
7ff8adafe9e4atagen2026-10-22 12:30 UTC500
            )
7ff8adafe9e4atagen2026-10-22 12:30 UTC501
            .unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC502
        assert_eq!(event.content.name.as_deref(), Some("My Room"));
7ff8adafe9e4atagen2026-10-22 12:30 UTC503
        assert_eq!(event.event_id.as_deref(), Some(event_id));
7ff8adafe9e4atagen2026-10-22 12:30 UTC504
7ff8adafe9e4atagen2026-10-22 12:30 UTC505
        let event =
7ff8adafe9e4atagen2026-10-22 12:30 UTC506
            serde_json::from_str::<MinimalStateEvent<PossiblyRedactedRoomNameEventContent>>(
7ff8adafe9e4atagen2026-10-22 12:30 UTC507
                r#"{"Redacted":{"content":{},"event_id":"$event"}}"#,
7ff8adafe9e4atagen2026-10-22 12:30 UTC508
            )
7ff8adafe9e4atagen2026-10-22 12:30 UTC509
            .unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC510
        assert_eq!(event.content.name, None);
7ff8adafe9e4atagen2026-10-22 12:30 UTC511
        assert_eq!(event.event_id.as_deref(), Some(event_id));
7ff8adafe9e4atagen2026-10-22 12:30 UTC512
7ff8adafe9e4atagen2026-10-22 12:30 UTC513
        // The new format works.
7ff8adafe9e4atagen2026-10-22 12:30 UTC514
        let event =
7ff8adafe9e4atagen2026-10-22 12:30 UTC515
            serde_json::from_str::<MinimalStateEvent<PossiblyRedactedRoomNameEventContent>>(
7ff8adafe9e4atagen2026-10-22 12:30 UTC516
                r#"{"PossiblyRedacted":{"content":{"name":"My Room"},"event_id":"$event"}}"#,
7ff8adafe9e4atagen2026-10-22 12:30 UTC517
            )
7ff8adafe9e4atagen2026-10-22 12:30 UTC518
            .unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC519
        assert_eq!(event.content.name.as_deref(), Some("My Room"));
7ff8adafe9e4atagen2026-10-22 12:30 UTC520
        assert_eq!(event.event_id.as_deref(), Some(event_id));
7ff8adafe9e4atagen2026-10-22 12:30 UTC521
7ff8adafe9e4atagen2026-10-22 12:30 UTC522
        let event =
7ff8adafe9e4atagen2026-10-22 12:30 UTC523
            serde_json::from_str::<MinimalStateEvent<PossiblyRedactedRoomNameEventContent>>(
7ff8adafe9e4atagen2026-10-22 12:30 UTC524
                r#"{"PossiblyRedacted":{"content":{},"event_id":"$event"}}"#,
7ff8adafe9e4atagen2026-10-22 12:30 UTC525
            )
7ff8adafe9e4atagen2026-10-22 12:30 UTC526
            .unwrap();
7ff8adafe9e4atagen2026-10-22 12:30 UTC527
        assert_eq!(event.content.name, None);
7ff8adafe9e4atagen2026-10-22 12:30 UTC528
        assert_eq!(event.event_id.as_deref(), Some(event_id));
7ff8adafe9e4atagen2026-10-22 12:30 UTC529
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC530
}