use std::borrow::Cow;
use ruma_common::serde::JsonObject;
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use serde_json::Value as JsonValue;
use super::{
AudioMessageEventContent, FileMessageEventContent, FormattedBody, ImageMessageEventContent,
VideoMessageEventContent,
};
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
pub struct GalleryMessageEventContent {
pub body: String,
#[serde(flatten)]
pub formatted: Option<FormattedBody>,
pub itemtypes: Vec<GalleryItemType>,
}
impl GalleryMessageEventContent {
pub fn new(
body: String,
formatted: Option<FormattedBody>,
itemtypes: Vec<GalleryItemType>,
) -> Self {
Self { body, formatted, itemtypes }
}
}
#[derive(Clone, Debug, Serialize)]
#[serde(tag = "itemtype")]
#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
pub enum GalleryItemType {
#[serde(rename = "m.audio")]
Audio(AudioMessageEventContent),
#[serde(rename = "m.file")]
File(FileMessageEventContent),
#[serde(rename = "m.image")]
Image(ImageMessageEventContent),
#[serde(rename = "m.video")]
Video(VideoMessageEventContent),
#[doc(hidden)]
#[serde(untagged)]
_Custom(CustomGalleryItemContent),
}
impl GalleryItemType {
pub fn new(itemtype: &str, body: String, data: JsonObject) -> serde_json::Result<Self> {
fn deserialize_variant<T: DeserializeOwned>(
body: String,
mut obj: JsonObject,
) -> serde_json::Result<T> {
obj.insert("body".into(), body.into());
serde_json::from_value(JsonValue::Object(obj))
}
Ok(match itemtype {
"m.audio" => Self::Audio(deserialize_variant(body, data)?),
"m.file" => Self::File(deserialize_variant(body, data)?),
"m.image" => Self::Image(deserialize_variant(body, data)?),
"m.video" => Self::Video(deserialize_variant(body, data)?),
_ => Self::_Custom(CustomGalleryItemContent {
itemtype: itemtype.to_owned(),
body,
data,
}),
})
}
pub fn itemtype(&self) -> &str {
match self {
Self::Audio(_) => "m.audio",
Self::File(_) => "m.file",
Self::Image(_) => "m.image",
Self::Video(_) => "m.video",
Self::_Custom(c) => &c.itemtype,
}
}
pub fn body(&self) -> &str {
match self {
GalleryItemType::Audio(m) => &m.body,
GalleryItemType::File(m) => &m.body,
GalleryItemType::Image(m) => &m.body,
GalleryItemType::Video(m) => &m.body,
GalleryItemType::_Custom(m) => &m.body,
}
}
pub fn data(&self) -> Cow<'_, JsonObject> {
fn serialize<T: Serialize>(obj: &T) -> JsonObject {
match serde_json::to_value(obj).expect("item type serialization to succeed") {
JsonValue::Object(mut obj) => {
obj.remove("body");
obj
}
_ => panic!("all item types must serialize to objects"),
}
}
match self {
Self::Audio(d) => Cow::Owned(serialize(d)),
Self::File(d) => Cow::Owned(serialize(d)),
Self::Image(d) => Cow::Owned(serialize(d)),
Self::Video(d) => Cow::Owned(serialize(d)),
Self::_Custom(c) => Cow::Borrowed(&c.data),
}
}
}
#[doc(hidden)]
#[derive(Clone, Debug, Serialize)]
pub struct CustomGalleryItemContent {
pub(super) itemtype: String,
pub(super) body: String,
#[serde(flatten)]
pub(super) data: JsonObject,
}