ruma_events/content.rs
1use std::fmt;
2
3use ruma_common::serde::{CanBeEmpty, Raw};
4use serde::{de::DeserializeOwned, Serialize};
5use serde_json::{from_str as from_json_str, value::RawValue as RawJsonValue};
6
7use super::{
8 EphemeralRoomEventType, GlobalAccountDataEventType, MessageLikeEventType,
9 RoomAccountDataEventType, StateEventType, ToDeviceEventType,
10};
11
12/// Extension trait for [`Raw<T>`].
13pub trait RawExt<T: EventContentFromType> {
14 /// Try to deserialize the JSON as an event's content with the given event type.
15 fn deserialize_with_type(&self, event_type: &str) -> serde_json::Result<T>;
16}
17
18impl<T> RawExt<T> for Raw<T>
19where
20 T: EventContentFromType,
21{
22 fn deserialize_with_type(&self, event_type: &str) -> serde_json::Result<T> {
23 T::from_parts(event_type, self.json())
24 }
25}
26
27/// An event content type with a statically-known event `type` value.
28///
29/// Note that the `TYPE` might not be the full event type. If `IsPrefix` is set to `True`, it only
30/// contains the statically-known prefix of the event type.
31///
32/// To only support full event types, the bound `StaticEventContent<IsPrefix = False>` can be used.
33pub trait StaticEventContent: Sized {
34 /// The statically-known part of the event type.
35 ///
36 /// If this is only the prefix of the event type, it should end with `.`, which is usually used
37 /// a separator in Matrix event types.
38 const TYPE: &'static str;
39 /// Whether the statically-known part of the event type is the prefix.
40 ///
41 /// Should be set to the [`True`] or [`False`] types.
42 ///
43 /// Ideally this should be a boolean associated constant, but [associated constant equality is
44 /// unstable], so this field could not be used as a bound. Instead we use an associated type so
45 /// we can rely on associated type equality.
46 ///
47 /// If this is set to [`False`], the `TYPE` is the full event type.
48 ///
49 /// [associated constant equality is unstable]: https://github.com/rust-lang/rust/issues/92827
50 type IsPrefix: BooleanType;
51}
52
53/// A trait for types representing a boolean value.
54pub trait BooleanType {
55 /// The boolean representation of this type.
56 fn as_bool() -> bool;
57}
58
59/// The equivalent of the `true` boolean.
60#[non_exhaustive]
61pub struct True;
62
63impl BooleanType for True {
64 fn as_bool() -> bool {
65 true
66 }
67}
68
69/// The equivalent of the `false` boolean.
70#[non_exhaustive]
71pub struct False;
72
73impl BooleanType for False {
74 fn as_bool() -> bool {
75 false
76 }
77}
78
79/// Content of a global account-data event.
80pub trait GlobalAccountDataEventContent: Sized + Serialize {
81 /// Get the event's type, like `m.push_rules`.
82 fn event_type(&self) -> GlobalAccountDataEventType;
83}
84
85/// Content of a room-specific account-data event.
86pub trait RoomAccountDataEventContent: Sized + Serialize {
87 /// Get the event's type, like `m.tag`.
88 fn event_type(&self) -> RoomAccountDataEventType;
89}
90
91/// Content of an ephemeral room event.
92pub trait EphemeralRoomEventContent: Sized + Serialize {
93 /// Get the event's type, like `m.receipt`.
94 fn event_type(&self) -> EphemeralRoomEventType;
95}
96
97/// Content of a non-redacted message-like event.
98pub trait MessageLikeEventContent: Sized + Serialize {
99 /// Get the event's type, like `m.room.message`.
100 fn event_type(&self) -> MessageLikeEventType;
101}
102
103/// Content of a redacted message-like event.
104pub trait RedactedMessageLikeEventContent: Sized + Serialize {
105 /// Get the event's type, like `m.room.message`.
106 fn event_type(&self) -> MessageLikeEventType;
107}
108
109/// Content of a non-redacted state event.
110pub trait StateEventContent: Sized + Serialize {
111 /// The type of the event's `state_key` field.
112 type StateKey: AsRef<str> + Clone + fmt::Debug + DeserializeOwned + Serialize;
113
114 /// Get the event's type, like `m.room.name`.
115 fn event_type(&self) -> StateEventType;
116}
117
118/// Content of a non-redacted state event with a corresponding possibly-redacted type.
119pub trait StaticStateEventContent: StateEventContent {
120 /// The possibly redacted form of the event's content.
121 type PossiblyRedacted: PossiblyRedactedStateEventContent;
122
123 /// The type of the event's `unsigned` field.
124 type Unsigned: Clone + fmt::Debug + Default + CanBeEmpty + DeserializeOwned;
125}
126
127/// Content of a redacted state event.
128pub trait RedactedStateEventContent: Sized + Serialize {
129 /// The type of the event's `state_key` field.
130 type StateKey: AsRef<str> + Clone + fmt::Debug + DeserializeOwned + Serialize;
131
132 /// Get the event's type, like `m.room.name`.
133 fn event_type(&self) -> StateEventType;
134}
135
136/// Content of a state event.
137pub trait PossiblyRedactedStateEventContent: Sized + Serialize {
138 /// The type of the event's `state_key` field.
139 type StateKey: AsRef<str> + Clone + fmt::Debug + DeserializeOwned + Serialize;
140
141 /// Get the event's type, like `m.room.name`.
142 fn event_type(&self) -> StateEventType;
143}
144
145/// Content of a to-device event.
146pub trait ToDeviceEventContent: Sized + Serialize {
147 /// Get the event's type, like `m.room_key`.
148 fn event_type(&self) -> ToDeviceEventType;
149}
150
151/// Event content that can be deserialized with its event type.
152pub trait EventContentFromType: Sized {
153 /// Constructs this event content from the given event type and JSON.
154 fn from_parts(event_type: &str, content: &RawJsonValue) -> serde_json::Result<Self>;
155}
156
157impl<T> EventContentFromType for T
158where
159 T: StaticEventContent + DeserializeOwned,
160{
161 fn from_parts(_event_type: &str, content: &RawJsonValue) -> serde_json::Result<Self> {
162 from_json_str(content.get())
163 }
164}