1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
use std::fmt;
use serde::{de::DeserializeOwned, Serialize};
use serde_json::value::RawValue as RawJsonValue;
use crate::serde::Raw;
use super::{
EphemeralRoomEventType, GlobalAccountDataEventType, MessageLikeEventType,
RoomAccountDataEventType, StateEventType, ToDeviceEventType,
};
/// The base trait that all event content types implement.
///
/// Use [`macros::EventContent`] to derive this traits. It is not meant to be implemented manually.
///
/// [`macros::EventContent`]: super::macros::EventContent
pub trait EventContent: Sized + Serialize {
/// The Rust enum for the event kind's known types.
type EventType;
/// Get the event's type, like `m.room.message`.
fn event_type(&self) -> Self::EventType;
/// Constructs the given event content.
#[doc(hidden)]
fn from_parts(event_type: &str, content: &RawJsonValue) -> serde_json::Result<Self>;
}
impl<T> Raw<T>
where
T: EventContent,
T::EventType: fmt::Display,
{
/// Try to deserialize the JSON as an event's content.
pub fn deserialize_content(&self, event_type: T::EventType) -> serde_json::Result<T> {
T::from_parts(&event_type.to_string(), self.json())
}
}
/// The base trait that all redacted event content types implement.
///
/// This trait's associated functions and methods should not be used to build
/// redacted events, prefer the `redact` method on `AnyStateEvent` and
/// `AnyMessageLikeEvent` and their "sync" and "stripped" counterparts.
/// The `RedactedEventContent` trait is an implementation detail, ruma makes no
/// API guarantees.
pub trait RedactedEventContent: EventContent {
/// Constructs the redacted event content.
///
/// If called for anything but "empty" redacted content this will error.
#[doc(hidden)]
fn empty(_event_type: &str) -> serde_json::Result<Self> {
Err(serde::de::Error::custom("this event is not redacted"))
}
/// Determines if the redacted event content needs to serialize fields.
#[doc(hidden)]
fn has_serialize_fields(&self) -> bool;
/// Determines if the redacted event content needs to deserialize fields.
#[doc(hidden)]
fn has_deserialize_fields() -> HasDeserializeFields;
}
/// `HasDeserializeFields` is used in the code generated by the `Event` derive
/// to aid in deserializing redacted events.
#[doc(hidden)]
#[derive(Debug)]
#[allow(clippy::exhaustive_enums)]
pub enum HasDeserializeFields {
/// Deserialize the event's content, failing if invalid.
True,
/// Return the redacted version of this event's content.
False,
/// `Optional` is used for `RedactedAliasesEventContent` since it has
/// an empty version and one with content left after redaction that
/// must be supported together.
Optional,
}
/// Trait for abstracting over event content structs.
///
/// … but *not* enums which don't always have an event type and kind (e.g. message vs state) that's
/// fixed / known at compile time.
pub trait StaticEventContent: EventContent {
/// The event's "kind".
///
/// See the type's documentation.
const KIND: EventKind;
/// The event type.
const TYPE: &'static str;
}
/// The "kind" of an event.
///
/// This corresponds directly to the event content marker traits.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum EventKind {
/// Global account data event kind.
GlobalAccountData,
/// Room account data event kind.
RoomAccountData,
/// Ephemeral room event kind.
EphemeralRoomData,
/// Message-like event kind.
///
/// Since redacted / non-redacted message-like events are used in the same places but have
/// different sets of fields, these two variations are treated as two closely-related event
/// kinds.
MessageLike {
/// Redacted variation?
redacted: bool,
},
/// State event kind.
///
/// Since redacted / non-redacted state events are used in the same places but have different
/// sets of fields, these two variations are treated as two closely-related event kinds.
State {
/// Redacted variation?
redacted: bool,
},
/// To-device event kind.
ToDevice,
/// Presence event kind.
Presence,
}
macro_rules! trait_aliases {
// need to use `,` instead of `+` because (1) path can't be followed by `+`
// and (2) `+` can't be used as a separator since it's a repetition operator
($(
$( #[doc = $docs:literal] )*
trait $id:ident = $( $def:path ),+;
)*) => {
$(
$( #[doc = $docs] )*
pub trait $id: $($def+)+ {}
impl<T: $($def+)+> $id for T {}
)*
}
}
trait_aliases! {
/// An alias for `EventContent<EventType = GlobalAccountDataEventType>`.
trait GlobalAccountDataEventContent = EventContent<EventType = GlobalAccountDataEventType>;
/// An alias for `EventContent<EventType = RoomAccountDataEventType>`.
trait RoomAccountDataEventContent = EventContent<EventType = RoomAccountDataEventType>;
/// An alias for `EventContent<EventType = EphemeralRoomEventType>`.
trait EphemeralRoomEventContent = EventContent<EventType = EphemeralRoomEventType>;
/// An alias for `EventContent<EventType = MessageLikeEventType>`.
trait MessageLikeEventContent = EventContent<EventType = MessageLikeEventType>;
/// An alias for `MessageLikeEventContent + RedactedEventContent`.
trait RedactedMessageLikeEventContent = MessageLikeEventContent, RedactedEventContent;
/// An alias for `StateEventContent + RedactedEventContent`.
trait RedactedStateEventContent = StateEventContent, RedactedEventContent;
/// An alias for `EventContent<EventType = ToDeviceEventType>`.
trait ToDeviceEventContent = EventContent<EventType = ToDeviceEventType>;
}
/// An alias for `EventContent<EventType = StateEventType>`.
pub trait StateEventContent: EventContent<EventType = StateEventType> {
/// The type of the event's `state_key` field.
type StateKey: AsRef<str> + Clone + fmt::Debug + DeserializeOwned + Serialize;
}