ruma_events/message/
historical_serde.rs1use serde::{Deserialize, Serialize};
6
7use super::{TextContentBlock, TextRepresentation};
8
9#[derive(Clone, Default, Serialize, Deserialize)]
11#[serde(try_from = "MessageContentBlockSerDeHelper")]
12#[serde(into = "MessageContentBlockSerDeHelper")]
13pub(crate) struct MessageContentBlock(Vec<TextRepresentation>);
14
15impl From<MessageContentBlock> for TextContentBlock {
16 fn from(value: MessageContentBlock) -> Self {
17 Self(value.0)
18 }
19}
20
21impl From<TextContentBlock> for MessageContentBlock {
22 fn from(value: TextContentBlock) -> Self {
23 Self(value.0)
24 }
25}
26
27#[derive(Default, Serialize, Deserialize)]
28pub(crate) struct MessageContentBlockSerDeHelper {
29 #[serde(rename = "org.matrix.msc1767.text", skip_serializing_if = "Option::is_none")]
31 text: Option<String>,
32
33 #[serde(rename = "org.matrix.msc1767.html", skip_serializing_if = "Option::is_none")]
35 html: Option<String>,
36
37 #[serde(rename = "org.matrix.msc1767.message", skip_serializing_if = "Option::is_none")]
39 message: Option<Vec<TextRepresentation>>,
40}
41
42impl TryFrom<MessageContentBlockSerDeHelper> for Vec<TextRepresentation> {
43 type Error = &'static str;
44
45 fn try_from(value: MessageContentBlockSerDeHelper) -> Result<Self, Self::Error> {
46 let MessageContentBlockSerDeHelper { text, html, message } = value;
47
48 if let Some(message) = message {
49 Ok(message)
50 } else {
51 let message: Vec<_> = html
52 .map(TextRepresentation::html)
53 .into_iter()
54 .chain(text.map(TextRepresentation::plain))
55 .collect();
56 if !message.is_empty() {
57 Ok(message)
58 } else {
59 Err(
60 "missing at least one of fields `org.matrix.msc1767.text`, `org.matrix.msc1767.html` or `org.matrix.msc1767.message`",
61 )
62 }
63 }
64 }
65}
66
67impl TryFrom<MessageContentBlockSerDeHelper> for MessageContentBlock {
68 type Error = &'static str;
69
70 fn try_from(value: MessageContentBlockSerDeHelper) -> Result<Self, Self::Error> {
71 Ok(Self(value.try_into()?))
72 }
73}
74
75impl From<Vec<TextRepresentation>> for MessageContentBlockSerDeHelper {
76 fn from(value: Vec<TextRepresentation>) -> Self {
77 let has_shortcut =
78 |message: &TextRepresentation| matches!(&*message.mimetype, "text/plain" | "text/html");
79
80 if value.iter().all(has_shortcut) {
81 let mut helper = Self::default();
82
83 for message in value.into_iter() {
84 if message.mimetype == "text/plain" {
85 helper.text = Some(message.body);
86 } else if message.mimetype == "text/html" {
87 helper.html = Some(message.body);
88 }
89 }
90
91 helper
92 } else {
93 Self { message: Some(value), ..Default::default() }
94 }
95 }
96}
97
98impl From<MessageContentBlock> for MessageContentBlockSerDeHelper {
99 fn from(value: MessageContentBlock) -> Self {
100 value.0.into()
101 }
102}