ruma_events/room/message/
relation_serde.rs1use ruma_common::{serde::JsonObject, OwnedEventId};
2use serde::{de, Deserialize, Deserializer, Serialize};
3use serde_json::Value as JsonValue;
4
5use super::{InReplyTo, Relation, RelationWithoutReplacement, Replacement, Thread};
6use crate::relation::CustomRelation;
7
8pub fn deserialize_relation<'de, D, C>(deserializer: D) -> Result<Option<Relation<C>>, D::Error>
26where
27 D: Deserializer<'de>,
28 C: Deserialize<'de>,
29{
30 let EventWithRelatesToDeHelper { relates_to, new_content } =
31 EventWithRelatesToDeHelper::deserialize(deserializer)?;
32 let Some(relates_to) = relates_to else {
33 return Ok(None);
34 };
35
36 let RelatesToDeHelper { in_reply_to, relation } = relates_to;
37
38 let rel = match relation {
39 RelationDeHelper::Known(relation) => match relation {
40 KnownRelationDeHelper::Replacement(ReplacementJsonRepr { event_id }) => {
41 match new_content {
42 Some(new_content) => {
43 Relation::Replacement(Replacement { event_id, new_content })
44 }
45 None => return Err(de::Error::missing_field("m.new_content")),
46 }
47 }
48 KnownRelationDeHelper::Thread(ThreadDeHelper { event_id, is_falling_back })
49 | KnownRelationDeHelper::ThreadUnstable(ThreadUnstableDeHelper {
50 event_id,
51 is_falling_back,
52 }) => Relation::Thread(Thread { event_id, in_reply_to, is_falling_back }),
53 },
54 RelationDeHelper::Unknown(c) => {
55 if let Some(in_reply_to) = in_reply_to {
56 Relation::Reply { in_reply_to }
57 } else {
58 Relation::_Custom(c)
59 }
60 }
61 };
62
63 Ok(Some(rel))
64}
65
66impl<C> Serialize for Relation<C>
67where
68 C: Clone + Serialize,
69{
70 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
71 where
72 S: serde::Serializer,
73 {
74 let (relates_to, new_content) = self.clone().into_parts();
75
76 EventWithRelatesToSerHelper { relates_to, new_content }.serialize(serializer)
77 }
78}
79
80#[derive(Deserialize)]
81pub(crate) struct EventWithRelatesToDeHelper<C> {
82 #[serde(rename = "m.relates_to")]
83 relates_to: Option<RelatesToDeHelper>,
84
85 #[serde(rename = "m.new_content")]
86 new_content: Option<C>,
87}
88
89#[derive(Deserialize)]
90pub(crate) struct RelatesToDeHelper {
91 #[serde(rename = "m.in_reply_to")]
92 in_reply_to: Option<InReplyTo>,
93
94 #[serde(flatten)]
95 relation: RelationDeHelper,
96}
97
98#[derive(Deserialize)]
99#[serde(untagged)]
100pub(crate) enum RelationDeHelper {
101 Known(KnownRelationDeHelper),
102 Unknown(CustomRelation),
103}
104
105#[derive(Deserialize)]
106#[serde(tag = "rel_type")]
107pub(crate) enum KnownRelationDeHelper {
108 #[serde(rename = "m.replace")]
109 Replacement(ReplacementJsonRepr),
110
111 #[serde(rename = "m.thread")]
112 Thread(ThreadDeHelper),
113
114 #[serde(rename = "io.element.thread")]
115 ThreadUnstable(ThreadUnstableDeHelper),
116}
117
118#[derive(Deserialize, Serialize)]
120pub(crate) struct ReplacementJsonRepr {
121 event_id: OwnedEventId,
122}
123
124#[derive(Deserialize)]
126pub(crate) struct ThreadDeHelper {
127 event_id: OwnedEventId,
128
129 #[serde(default)]
130 is_falling_back: bool,
131}
132
133#[derive(Deserialize)]
135pub(crate) struct ThreadUnstableDeHelper {
136 event_id: OwnedEventId,
137
138 #[serde(rename = "io.element.show_reply", default)]
139 is_falling_back: bool,
140}
141
142#[derive(Serialize)]
143pub(super) struct EventWithRelatesToSerHelper<C> {
144 #[serde(rename = "m.relates_to")]
145 relates_to: RelationSerHelper,
146
147 #[serde(rename = "m.new_content", skip_serializing_if = "Option::is_none")]
148 new_content: Option<C>,
149}
150
151#[derive(Serialize)]
153#[serde(tag = "rel_type")]
154pub(super) enum RelationSerHelper {
155 #[serde(rename = "m.replace")]
157 Replacement(ReplacementJsonRepr),
158
159 #[serde(untagged)]
161 Thread(Thread),
162
163 #[serde(untagged)]
165 Custom(CustomSerHelper),
166}
167
168impl<C> Relation<C> {
169 fn into_parts(self) -> (RelationSerHelper, Option<C>) {
170 match self {
171 Relation::Replacement(Replacement { event_id, new_content }) => (
172 RelationSerHelper::Replacement(ReplacementJsonRepr { event_id }),
173 Some(new_content),
174 ),
175 Relation::Reply { in_reply_to } => {
176 (RelationSerHelper::Custom(in_reply_to.into()), None)
177 }
178 Relation::Thread(t) => (RelationSerHelper::Thread(t), None),
179 Relation::_Custom(c) => (RelationSerHelper::Custom(c.into()), None),
180 }
181 }
182
183 pub(super) fn serialize_data(&self) -> JsonObject
184 where
185 C: Clone,
186 {
187 let (relates_to, _) = self.clone().into_parts();
188
189 match serde_json::to_value(relates_to).expect("relation serialization to succeed") {
190 JsonValue::Object(mut obj) => {
191 obj.remove("rel_type");
192 obj
193 }
194 _ => panic!("all relations must serialize to objects"),
195 }
196 }
197}
198
199#[derive(Default, Serialize)]
200pub(super) struct CustomSerHelper {
201 #[serde(rename = "m.in_reply_to", skip_serializing_if = "Option::is_none")]
202 in_reply_to: Option<InReplyTo>,
203
204 #[serde(flatten, skip_serializing_if = "JsonObject::is_empty")]
205 data: JsonObject,
206}
207
208impl From<InReplyTo> for CustomSerHelper {
209 fn from(value: InReplyTo) -> Self {
210 Self { in_reply_to: Some(value), data: JsonObject::new() }
211 }
212}
213
214impl From<CustomRelation> for CustomSerHelper {
215 fn from(CustomRelation(data): CustomRelation) -> Self {
216 Self { in_reply_to: None, data }
217 }
218}
219
220impl From<&RelationWithoutReplacement> for RelationSerHelper {
221 fn from(value: &RelationWithoutReplacement) -> Self {
222 match value.clone() {
223 RelationWithoutReplacement::Reply { in_reply_to } => {
224 RelationSerHelper::Custom(in_reply_to.into())
225 }
226 RelationWithoutReplacement::Thread(t) => RelationSerHelper::Thread(t),
227 RelationWithoutReplacement::_Custom(c) => RelationSerHelper::Custom(c.into()),
228 }
229 }
230}
231
232impl Serialize for RelationWithoutReplacement {
233 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
234 where
235 S: serde::Serializer,
236 {
237 RelationSerHelper::from(self).serialize(serializer)
238 }
239}
240
241impl RelationWithoutReplacement {
242 pub(super) fn serialize_data(&self) -> JsonObject {
243 let helper = RelationSerHelper::from(self);
244
245 match serde_json::to_value(helper).expect("relation serialization to succeed") {
246 JsonValue::Object(mut obj) => {
247 obj.remove("rel_type");
248 obj
249 }
250 _ => panic!("all relations must serialize to objects"),
251 }
252 }
253}