Files
matrix-rust-sdk/crates/matrix-sdk-base/src/utils.rs
2023-01-25 18:01:12 +01:00

287 lines
10 KiB
Rust

use ruma::{
assign,
events::{
room::{
avatar::{RoomAvatarEventContent, StrippedRoomAvatarEvent},
canonical_alias::{RoomCanonicalAliasEventContent, StrippedRoomCanonicalAliasEvent},
create::{RoomCreateEventContent, StrippedRoomCreateEvent},
guest_access::{
RedactedRoomGuestAccessEventContent, RoomGuestAccessEventContent,
StrippedRoomGuestAccessEvent,
},
history_visibility::{
RoomHistoryVisibilityEventContent, StrippedRoomHistoryVisibilityEvent,
},
join_rules::{RoomJoinRulesEventContent, StrippedRoomJoinRulesEvent},
member::{MembershipState, RoomMemberEventContent},
name::{RoomNameEventContent, StrippedRoomNameEvent},
tombstone::{
RedactedRoomTombstoneEventContent, RoomTombstoneEventContent,
StrippedRoomTombstoneEvent,
},
topic::{RedactedRoomTopicEventContent, RoomTopicEventContent, StrippedRoomTopicEvent},
},
RedactContent, RedactedStateEventContent, StateEventContent, StaticStateEventContent,
SyncStateEvent,
},
EventId, OwnedEventId, RoomVersionId,
};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
// #[serde(bound)] instead of DeserializeOwned in type where clause does not
// work, it can only be a single bound that replaces the default and if a helper
// trait is used, the compiler still complains about Deserialize not being
// implemented for C::Redacted.
//
// It is unclear why a Serialize bound on C::Redacted is not also required.
/// A minimal state event.
///
/// This type can holding an possibly-redacted state event with an optional
/// event ID. The event ID is optional so this type can also hold events from
/// invited rooms, where event IDs are not available.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(bound(
serialize = "C: Serialize, C::Redacted: Serialize",
deserialize = "C: DeserializeOwned, C::Redacted: DeserializeOwned"
))]
pub enum MinimalStateEvent<C: StateEventContent + RedactContent>
where
C::Redacted: RedactedStateEventContent,
{
/// An unredacted event.
Original(OriginalMinimalStateEvent<C>),
/// A redacted event.
Redacted(RedactedMinimalStateEvent<C::Redacted>),
}
/// An unredacted minimal state event.
///
/// For more details see [`MinimalStateEvent`].
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct OriginalMinimalStateEvent<C>
where
C: StateEventContent,
{
/// The event's content.
pub content: C,
/// The event's ID, if known.
pub event_id: Option<OwnedEventId>,
}
/// A redacted minimal state event.
///
/// For more details see [`MinimalStateEvent`].
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RedactedMinimalStateEvent<C>
where
C: RedactedStateEventContent,
{
/// The event's content.
pub content: C,
/// The event's ID, if known.
pub event_id: Option<OwnedEventId>,
}
impl<C> MinimalStateEvent<C>
where
C: StateEventContent + RedactContent,
C::Redacted: RedactedStateEventContent,
{
/// Get the inner event's ID.
pub fn event_id(&self) -> Option<&EventId> {
match self {
MinimalStateEvent::Original(ev) => ev.event_id.as_deref(),
MinimalStateEvent::Redacted(ev) => ev.event_id.as_deref(),
}
}
/// Returns the inner event, if it isn't redacted.
pub fn as_original(&self) -> Option<&OriginalMinimalStateEvent<C>> {
match self {
MinimalStateEvent::Original(ev) => Some(ev),
MinimalStateEvent::Redacted(_) => None,
}
}
/// Converts `self` to the inner `OriginalMinimalStateEvent<C>`, if it isn't
/// redacted.
pub fn into_original(self) -> Option<OriginalMinimalStateEvent<C>> {
match self {
MinimalStateEvent::Original(ev) => Some(ev),
MinimalStateEvent::Redacted(_) => None,
}
}
/// Redacts this event.
///
/// Does nothing if it is already redacted.
pub fn redact(&mut self, room_version: &RoomVersionId)
where
C: Clone,
{
if let MinimalStateEvent::Original(ev) = self {
*self = MinimalStateEvent::Redacted(RedactedMinimalStateEvent {
content: ev.content.clone().redact(room_version),
event_id: ev.event_id.clone(),
});
}
}
}
/// A minimal `m.room.member` event.
pub type MinimalRoomMemberEvent = MinimalStateEvent<RoomMemberEventContent>;
impl MinimalRoomMemberEvent {
/// Obtain the membership state, regardless of whether this event is
/// redacted.
pub fn membership(&self) -> &MembershipState {
match self {
MinimalStateEvent::Original(ev) => &ev.content.membership,
MinimalStateEvent::Redacted(ev) => &ev.content.membership,
}
}
}
impl<C> From<SyncStateEvent<C>> for MinimalStateEvent<C>
where
C: StaticStateEventContent + RedactContent,
C::Redacted: RedactedStateEventContent,
{
fn from(ev: SyncStateEvent<C>) -> Self {
match ev {
SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent {
content: ev.content,
event_id: Some(ev.event_id),
}),
SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent {
content: ev.content,
event_id: Some(ev.event_id),
}),
}
}
}
impl<C> From<&SyncStateEvent<C>> for MinimalStateEvent<C>
where
C: Clone + StaticStateEventContent + RedactContent,
C::Redacted: Clone + RedactedStateEventContent,
{
fn from(ev: &SyncStateEvent<C>) -> Self {
match ev {
SyncStateEvent::Original(ev) => Self::Original(OriginalMinimalStateEvent {
content: ev.content.clone(),
event_id: Some(ev.event_id.clone()),
}),
SyncStateEvent::Redacted(ev) => Self::Redacted(RedactedMinimalStateEvent {
content: ev.content.clone(),
event_id: Some(ev.event_id.clone()),
}),
}
}
}
impl From<&StrippedRoomAvatarEvent> for MinimalStateEvent<RoomAvatarEventContent> {
fn from(event: &StrippedRoomAvatarEvent) -> Self {
let content = assign!(RoomAvatarEventContent::new(), {
info: event.content.info.clone(),
url: event.content.url.clone(),
});
// event might actually be redacted, there is no way to tell for
// stripped state events.
Self::Original(OriginalMinimalStateEvent { content, event_id: None })
}
}
impl From<&StrippedRoomNameEvent> for MinimalStateEvent<RoomNameEventContent> {
fn from(event: &StrippedRoomNameEvent) -> Self {
let content = RoomNameEventContent::new(event.content.name.clone());
Self::Original(OriginalMinimalStateEvent { content, event_id: None })
}
}
impl From<&StrippedRoomCreateEvent> for MinimalStateEvent<RoomCreateEventContent> {
fn from(event: &StrippedRoomCreateEvent) -> Self {
let content = assign!(RoomCreateEventContent::new(event.content.creator.clone()), {
federate: event.content.federate,
room_version: event.content.room_version.clone(),
predecessor: event.content.predecessor.clone(),
room_type: event.content.room_type.clone(),
});
Self::Original(OriginalMinimalStateEvent { content, event_id: None })
}
}
impl From<&StrippedRoomHistoryVisibilityEvent>
for MinimalStateEvent<RoomHistoryVisibilityEventContent>
{
fn from(event: &StrippedRoomHistoryVisibilityEvent) -> Self {
let content =
RoomHistoryVisibilityEventContent::new(event.content.history_visibility.clone());
Self::Original(OriginalMinimalStateEvent { content, event_id: None })
}
}
impl From<&StrippedRoomGuestAccessEvent> for MinimalStateEvent<RoomGuestAccessEventContent> {
fn from(event: &StrippedRoomGuestAccessEvent) -> Self {
match &event.content.guest_access {
Some(guest_access) => {
let content = RoomGuestAccessEventContent::new(guest_access.clone());
Self::Original(OriginalMinimalStateEvent { content, event_id: None })
}
None => {
let content = RedactedRoomGuestAccessEventContent::new();
Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
}
}
}
}
impl From<&StrippedRoomJoinRulesEvent> for MinimalStateEvent<RoomJoinRulesEventContent> {
fn from(event: &StrippedRoomJoinRulesEvent) -> Self {
let content = RoomJoinRulesEventContent::new(event.content.join_rule.clone());
Self::Original(OriginalMinimalStateEvent { content, event_id: None })
}
}
impl From<&StrippedRoomCanonicalAliasEvent> for MinimalStateEvent<RoomCanonicalAliasEventContent> {
fn from(event: &StrippedRoomCanonicalAliasEvent) -> Self {
let content = assign!(RoomCanonicalAliasEventContent::new(), {
alias: event.content.alias.clone(),
alt_aliases: event.content.alt_aliases.clone(),
});
Self::Original(OriginalMinimalStateEvent { content, event_id: None })
}
}
impl From<&StrippedRoomTopicEvent> for MinimalStateEvent<RoomTopicEventContent> {
fn from(event: &StrippedRoomTopicEvent) -> Self {
match &event.content.topic {
Some(topic) => {
let content = RoomTopicEventContent::new(topic.clone());
Self::Original(OriginalMinimalStateEvent { content, event_id: None })
}
None => {
let content = RedactedRoomTopicEventContent::new();
Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
}
}
}
}
impl From<&StrippedRoomTombstoneEvent> for MinimalStateEvent<RoomTombstoneEventContent> {
fn from(event: &StrippedRoomTombstoneEvent) -> Self {
match (&event.content.body, &event.content.replacement_room) {
(Some(body), Some(replacement_room)) => {
let content =
RoomTombstoneEventContent::new(body.clone(), replacement_room.clone());
Self::Original(OriginalMinimalStateEvent { content, event_id: None })
}
_ => {
let content = RedactedRoomTombstoneEventContent::new();
Self::Redacted(RedactedMinimalStateEvent { content, event_id: None })
}
}
}
}