ruma_events/room/message/
content_serde.rs

1//! `Deserialize` implementation for RoomMessageEventContent and MessageType.
2
3use ruma_common::serde::from_raw_json_value;
4use serde::{de, Deserialize};
5use serde_json::value::RawValue as RawJsonValue;
6
7#[cfg(feature = "unstable-msc4274")]
8use super::gallery::GalleryItemType;
9use super::{
10    relation_serde::deserialize_relation, MessageType, RoomMessageEventContent,
11    RoomMessageEventContentWithoutRelation,
12};
13use crate::Mentions;
14
15impl<'de> Deserialize<'de> for RoomMessageEventContent {
16    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
17    where
18        D: de::Deserializer<'de>,
19    {
20        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
21
22        let mut deserializer = serde_json::Deserializer::from_str(json.get());
23        let relates_to = deserialize_relation(&mut deserializer).map_err(de::Error::custom)?;
24
25        let MentionsDeHelper { mentions } = from_raw_json_value(&json)?;
26
27        Ok(Self { msgtype: from_raw_json_value(&json)?, relates_to, mentions })
28    }
29}
30
31impl<'de> Deserialize<'de> for RoomMessageEventContentWithoutRelation {
32    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
33    where
34        D: de::Deserializer<'de>,
35    {
36        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
37
38        let MentionsDeHelper { mentions } = from_raw_json_value(&json)?;
39
40        Ok(Self { msgtype: from_raw_json_value(&json)?, mentions })
41    }
42}
43
44#[derive(Deserialize)]
45struct MentionsDeHelper {
46    #[serde(rename = "m.mentions")]
47    mentions: Option<Mentions>,
48}
49
50/// Helper struct to determine the msgtype from a `serde_json::value::RawValue`
51#[derive(Debug, Deserialize)]
52struct MessageTypeDeHelper {
53    /// The message type field
54    msgtype: String,
55}
56
57impl<'de> Deserialize<'de> for MessageType {
58    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
59    where
60        D: de::Deserializer<'de>,
61    {
62        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
63        let MessageTypeDeHelper { msgtype } = from_raw_json_value(&json)?;
64
65        Ok(match msgtype.as_ref() {
66            "m.audio" => Self::Audio(from_raw_json_value(&json)?),
67            "m.emote" => Self::Emote(from_raw_json_value(&json)?),
68            "m.file" => Self::File(from_raw_json_value(&json)?),
69            #[cfg(feature = "unstable-msc4274")]
70            "dm.filament.gallery" => Self::Gallery(from_raw_json_value(&json)?),
71            "m.image" => Self::Image(from_raw_json_value(&json)?),
72            "m.location" => Self::Location(from_raw_json_value(&json)?),
73            "m.notice" => Self::Notice(from_raw_json_value(&json)?),
74            "m.server_notice" => Self::ServerNotice(from_raw_json_value(&json)?),
75            "m.text" => Self::Text(from_raw_json_value(&json)?),
76            "m.video" => Self::Video(from_raw_json_value(&json)?),
77            "m.key.verification.request" => Self::VerificationRequest(from_raw_json_value(&json)?),
78            _ => Self::_Custom(from_raw_json_value(&json)?),
79        })
80    }
81}
82
83/// Helper struct to determine the itemtype from a `serde_json::value::RawValue`
84#[derive(Debug, Deserialize)]
85#[cfg(feature = "unstable-msc4274")]
86struct ItemTypeDeHelper {
87    /// The item type field
88    itemtype: String,
89}
90
91#[cfg(feature = "unstable-msc4274")]
92impl<'de> Deserialize<'de> for GalleryItemType {
93    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
94    where
95        D: de::Deserializer<'de>,
96    {
97        let json = Box::<RawJsonValue>::deserialize(deserializer)?;
98        let ItemTypeDeHelper { itemtype } = from_raw_json_value(&json)?;
99
100        Ok(match itemtype.as_ref() {
101            "m.audio" => Self::Audio(from_raw_json_value(&json)?),
102            "m.file" => Self::File(from_raw_json_value(&json)?),
103            "m.image" => Self::Image(from_raw_json_value(&json)?),
104            "m.video" => Self::Video(from_raw_json_value(&json)?),
105            _ => Self::_Custom(from_raw_json_value(&json)?),
106        })
107    }
108}
109
110#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/112615
111#[cfg(feature = "unstable-msc3488")]
112pub(in super::super) mod msc3488 {
113    use ruma_common::MilliSecondsSinceUnixEpoch;
114    use serde::{Deserialize, Serialize};
115
116    use crate::{
117        location::{AssetContent, LocationContent},
118        message::historical_serde::MessageContentBlock,
119        room::message::{LocationInfo, LocationMessageEventContent},
120    };
121
122    /// Deserialize helper type for `LocationMessageEventContent` with unstable fields from msc3488.
123    #[derive(Serialize, Deserialize)]
124    #[serde(tag = "msgtype", rename = "m.location")]
125    pub(in super::super) struct LocationMessageEventContentSerDeHelper {
126        pub body: String,
127
128        pub geo_uri: String,
129
130        #[serde(skip_serializing_if = "Option::is_none")]
131        pub info: Option<Box<LocationInfo>>,
132
133        #[serde(flatten)]
134        pub message: Option<MessageContentBlock>,
135
136        #[serde(rename = "org.matrix.msc3488.location", skip_serializing_if = "Option::is_none")]
137        pub location: Option<LocationContent>,
138
139        #[serde(rename = "org.matrix.msc3488.asset", skip_serializing_if = "Option::is_none")]
140        pub asset: Option<AssetContent>,
141
142        #[serde(rename = "org.matrix.msc3488.ts", skip_serializing_if = "Option::is_none")]
143        pub ts: Option<MilliSecondsSinceUnixEpoch>,
144    }
145
146    impl From<LocationMessageEventContent> for LocationMessageEventContentSerDeHelper {
147        fn from(value: LocationMessageEventContent) -> Self {
148            let LocationMessageEventContent { body, geo_uri, info, message, location, asset, ts } =
149                value;
150
151            Self { body, geo_uri, info, message: message.map(Into::into), location, asset, ts }
152        }
153    }
154
155    impl From<LocationMessageEventContentSerDeHelper> for LocationMessageEventContent {
156        fn from(value: LocationMessageEventContentSerDeHelper) -> Self {
157            let LocationMessageEventContentSerDeHelper {
158                body,
159                geo_uri,
160                info,
161                message,
162                location,
163                asset,
164                ts,
165            } = value;
166
167            LocationMessageEventContent {
168                body,
169                geo_uri,
170                info,
171                message: message.map(Into::into),
172                location,
173                asset,
174                ts,
175            }
176        }
177    }
178}