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::{Deserialize, de};
5use serde_json::value::RawValue as RawJsonValue;
6
7#[cfg(feature = "unstable-msc4274")]
8use super::gallery::GalleryItemType;
9use super::{
10    MessageType, RoomMessageEventContent, RoomMessageEventContentWithoutRelation,
11    relation_serde::deserialize_relation,
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    pub(in super::super) struct LocationMessageEventContentSerDeHelper {
125        pub body: String,
126
127        pub geo_uri: String,
128
129        #[serde(skip_serializing_if = "Option::is_none")]
130        pub info: Option<Box<LocationInfo>>,
131
132        #[serde(flatten)]
133        pub message: Option<MessageContentBlock>,
134
135        #[serde(rename = "org.matrix.msc3488.location", skip_serializing_if = "Option::is_none")]
136        pub location: Option<LocationContent>,
137
138        #[serde(rename = "org.matrix.msc3488.asset", skip_serializing_if = "Option::is_none")]
139        pub asset: Option<AssetContent>,
140
141        #[serde(rename = "org.matrix.msc3488.ts", skip_serializing_if = "Option::is_none")]
142        pub ts: Option<MilliSecondsSinceUnixEpoch>,
143    }
144
145    impl From<LocationMessageEventContent> for LocationMessageEventContentSerDeHelper {
146        fn from(value: LocationMessageEventContent) -> Self {
147            let LocationMessageEventContent { body, geo_uri, info, message, location, asset, ts } =
148                value;
149
150            Self { body, geo_uri, info, message: message.map(Into::into), location, asset, ts }
151        }
152    }
153
154    impl From<LocationMessageEventContentSerDeHelper> for LocationMessageEventContent {
155        fn from(value: LocationMessageEventContentSerDeHelper) -> Self {
156            let LocationMessageEventContentSerDeHelper {
157                body,
158                geo_uri,
159                info,
160                message,
161                location,
162                asset,
163                ts,
164            } = value;
165
166            LocationMessageEventContent {
167                body,
168                geo_uri,
169                info,
170                message: message.map(Into::into),
171                location,
172                asset,
173                ts,
174            }
175        }
176    }
177}