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