ruma_events/room/message/
content_serde.rs1use ruma_common::serde::from_raw_json_value;
4#[cfg(feature = "unstable-msc4274")]
5use serde::Serialize;
6use serde::{de, Deserialize};
7use serde_json::value::RawValue as RawJsonValue;
8#[cfg(feature = "unstable-msc4274")]
9use serde_json::Value as JsonValue;
10
11#[cfg(feature = "unstable-msc4274")]
12use super::gallery::GalleryItemType;
13use super::{
14 relation_serde::deserialize_relation, MessageType, RoomMessageEventContent,
15 RoomMessageEventContentWithoutRelation,
16};
17use crate::Mentions;
18
19impl<'de> Deserialize<'de> for RoomMessageEventContent {
20 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
21 where
22 D: de::Deserializer<'de>,
23 {
24 let json = Box::<RawJsonValue>::deserialize(deserializer)?;
25
26 let mut deserializer = serde_json::Deserializer::from_str(json.get());
27 let relates_to = deserialize_relation(&mut deserializer).map_err(de::Error::custom)?;
28
29 let MentionsDeHelper { mentions } = from_raw_json_value(&json)?;
30
31 Ok(Self { msgtype: from_raw_json_value(&json)?, relates_to, mentions })
32 }
33}
34
35impl<'de> Deserialize<'de> for RoomMessageEventContentWithoutRelation {
36 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
37 where
38 D: de::Deserializer<'de>,
39 {
40 let json = Box::<RawJsonValue>::deserialize(deserializer)?;
41
42 let MentionsDeHelper { mentions } = from_raw_json_value(&json)?;
43
44 Ok(Self { msgtype: from_raw_json_value(&json)?, mentions })
45 }
46}
47
48#[derive(Deserialize)]
49struct MentionsDeHelper {
50 #[serde(rename = "m.mentions")]
51 mentions: Option<Mentions>,
52}
53
54#[derive(Debug, Deserialize)]
56struct MessageTypeDeHelper {
57 msgtype: String,
59}
60
61impl<'de> Deserialize<'de> for MessageType {
62 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
63 where
64 D: de::Deserializer<'de>,
65 {
66 let json = Box::<RawJsonValue>::deserialize(deserializer)?;
67 let MessageTypeDeHelper { msgtype } = from_raw_json_value(&json)?;
68
69 Ok(match msgtype.as_ref() {
70 "m.audio" => Self::Audio(from_raw_json_value(&json)?),
71 "m.emote" => Self::Emote(from_raw_json_value(&json)?),
72 "m.file" => Self::File(from_raw_json_value(&json)?),
73 #[cfg(feature = "unstable-msc4274")]
74 "dm.filament.gallery" => Self::Gallery(from_raw_json_value(&json)?),
75 "m.image" => Self::Image(from_raw_json_value(&json)?),
76 "m.location" => Self::Location(from_raw_json_value(&json)?),
77 "m.notice" => Self::Notice(from_raw_json_value(&json)?),
78 "m.server_notice" => Self::ServerNotice(from_raw_json_value(&json)?),
79 "m.text" => Self::Text(from_raw_json_value(&json)?),
80 "m.video" => Self::Video(from_raw_json_value(&json)?),
81 "m.key.verification.request" => Self::VerificationRequest(from_raw_json_value(&json)?),
82 _ => Self::_Custom(from_raw_json_value(&json)?),
83 })
84 }
85}
86
87#[derive(Debug, Deserialize)]
89#[cfg(feature = "unstable-msc4274")]
90struct ItemTypeDeHelper {
91 itemtype: String,
93}
94
95#[cfg(feature = "unstable-msc4274")]
96impl<'de> Deserialize<'de> for GalleryItemType {
97 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
98 where
99 D: de::Deserializer<'de>,
100 {
101 let json = Box::<RawJsonValue>::deserialize(deserializer)?;
102 let ItemTypeDeHelper { itemtype } = from_raw_json_value(&json)?;
103
104 Ok(match itemtype.as_ref() {
105 "m.audio" => Self::Audio(from_raw_json_value(&json)?),
106 "m.file" => Self::File(from_raw_json_value(&json)?),
107 "m.image" => Self::Image(from_raw_json_value(&json)?),
108 "m.video" => Self::Video(from_raw_json_value(&json)?),
109 _ => Self::_Custom(from_raw_json_value(&json)?),
110 })
111 }
112}
113
114#[cfg(feature = "unstable-msc4274")]
115impl Serialize for GalleryItemType {
116 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117 where
118 S: serde::Serializer,
119 {
120 let mut map = match self {
121 GalleryItemType::Audio(content) => {
122 serde_json::to_value(content).map_err(serde::ser::Error::custom)?
123 }
124 GalleryItemType::File(content) => {
125 serde_json::to_value(content).map_err(serde::ser::Error::custom)?
126 }
127 GalleryItemType::Image(content) => {
128 serde_json::to_value(content).map_err(serde::ser::Error::custom)?
129 }
130 GalleryItemType::Video(content) => {
131 serde_json::to_value(content).map_err(serde::ser::Error::custom)?
132 }
133 GalleryItemType::_Custom(content) => {
134 serde_json::to_value(content).map_err(serde::ser::Error::custom)?
135 }
136 }
137 .as_object()
138 .cloned()
139 .unwrap_or_default();
140
141 map.insert("itemtype".to_owned(), JsonValue::String(self.itemtype().to_owned()));
142 map.remove("msgtype");
143
144 map.serialize(serializer)
145 }
146}
147
148#[allow(unreachable_pub)] #[cfg(feature = "unstable-msc3488")]
150pub(in super::super) mod msc3488 {
151 use ruma_common::MilliSecondsSinceUnixEpoch;
152 use serde::{Deserialize, Serialize};
153
154 use crate::{
155 location::{AssetContent, LocationContent},
156 message::historical_serde::MessageContentBlock,
157 room::message::{LocationInfo, LocationMessageEventContent},
158 };
159
160 #[derive(Serialize, Deserialize)]
162 #[serde(tag = "msgtype", rename = "m.location")]
163 pub(in super::super) struct LocationMessageEventContentSerDeHelper {
164 pub body: String,
165
166 pub geo_uri: String,
167
168 #[serde(skip_serializing_if = "Option::is_none")]
169 pub info: Option<Box<LocationInfo>>,
170
171 #[serde(flatten)]
172 pub message: Option<MessageContentBlock>,
173
174 #[serde(rename = "org.matrix.msc3488.location", skip_serializing_if = "Option::is_none")]
175 pub location: Option<LocationContent>,
176
177 #[serde(rename = "org.matrix.msc3488.asset", skip_serializing_if = "Option::is_none")]
178 pub asset: Option<AssetContent>,
179
180 #[serde(rename = "org.matrix.msc3488.ts", skip_serializing_if = "Option::is_none")]
181 pub ts: Option<MilliSecondsSinceUnixEpoch>,
182 }
183
184 impl From<LocationMessageEventContent> for LocationMessageEventContentSerDeHelper {
185 fn from(value: LocationMessageEventContent) -> Self {
186 let LocationMessageEventContent { body, geo_uri, info, message, location, asset, ts } =
187 value;
188
189 Self { body, geo_uri, info, message: message.map(Into::into), location, asset, ts }
190 }
191 }
192
193 impl From<LocationMessageEventContentSerDeHelper> for LocationMessageEventContent {
194 fn from(value: LocationMessageEventContentSerDeHelper) -> Self {
195 let LocationMessageEventContentSerDeHelper {
196 body,
197 geo_uri,
198 info,
199 message,
200 location,
201 asset,
202 ts,
203 } = value;
204
205 LocationMessageEventContent {
206 body,
207 geo_uri,
208 info,
209 message: message.map(Into::into),
210 location,
211 asset,
212 ts,
213 }
214 }
215 }
216}