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