ruma_events/room/message/
content_serde.rs

1//! `Deserialize` implementation for RoomMessageEventContent and MessageType.
2
3use 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/// Helper struct to determine the msgtype from a `serde_json::value::RawValue`
55#[derive(Debug, Deserialize)]
56struct MessageTypeDeHelper {
57    /// The message type field
58    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/// Helper struct to determine the itemtype from a `serde_json::value::RawValue`
88#[derive(Debug, Deserialize)]
89#[cfg(feature = "unstable-msc4274")]
90struct ItemTypeDeHelper {
91    /// The item type field
92    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)] // https://github.com/rust-lang/rust/issues/112615
149#[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    /// Deserialize helper type for `LocationMessageEventContent` with unstable fields from msc3488.
161    #[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}