events: Avoid unnecessary allocations during conversion
This commit is contained in:
parent
96155915fe
commit
bda17c3662
@ -89,12 +89,17 @@ impl AudioEventContent {
|
|||||||
#[cfg(feature = "unstable-msc3245")]
|
#[cfg(feature = "unstable-msc3245")]
|
||||||
voice: _,
|
voice: _,
|
||||||
} = content;
|
} = content;
|
||||||
|
let AudioInfo { duration, mimetype, size } = info.map(|info| *info).unwrap_or_default();
|
||||||
|
|
||||||
let message = message.unwrap_or_else(|| MessageContent::plain(body));
|
let message = message.unwrap_or_else(|| MessageContent::plain(body));
|
||||||
let file = file.unwrap_or_else(|| {
|
let file = file.unwrap_or_else(|| {
|
||||||
FileContent::from_room_message_content(source, info.as_deref(), None)
|
FileContent::from_room_message_content(source, None, mimetype, size)
|
||||||
|
});
|
||||||
|
let audio = audio.unwrap_or_else(|| {
|
||||||
|
let mut content = AudioContent::new();
|
||||||
|
content.duration = duration;
|
||||||
|
content
|
||||||
});
|
});
|
||||||
let audio = audio.or_else(|| info.as_deref().map(Into::into)).unwrap_or_default();
|
|
||||||
|
|
||||||
Self { message, file, audio, relates_to }
|
Self { message, file, audio, relates_to }
|
||||||
}
|
}
|
||||||
@ -136,19 +141,17 @@ impl AudioContent {
|
|||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new `AudioContent` with the given duration.
|
||||||
|
pub(crate) fn from_room_message_content(duration: Duration) -> Self {
|
||||||
|
Self { duration: Some(duration), ..Default::default() }
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether this `AudioContent` is empty.
|
/// Whether this `AudioContent` is empty.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.duration.is_none() && self.waveform.is_none()
|
self.duration.is_none() && self.waveform.is_none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&AudioInfo> for AudioContent {
|
|
||||||
fn from(info: &AudioInfo) -> Self {
|
|
||||||
let AudioInfo { duration, .. } = info;
|
|
||||||
Self { duration: duration.to_owned(), ..Default::default() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The waveform representation of audio content.
|
/// The waveform representation of audio content.
|
||||||
///
|
///
|
||||||
/// Must include between 30 and 120 `Amplitude`s.
|
/// Must include between 30 and 120 `Amplitude`s.
|
||||||
|
@ -12,10 +12,9 @@ use super::{
|
|||||||
message::MessageContent,
|
message::MessageContent,
|
||||||
room::{
|
room::{
|
||||||
message::{
|
message::{
|
||||||
AudioInfo, FileInfo, FileMessageEventContent, MessageType, Relation,
|
FileInfo, FileMessageEventContent, MessageType, Relation, RoomMessageEventContent,
|
||||||
RoomMessageEventContent, VideoInfo,
|
|
||||||
},
|
},
|
||||||
EncryptedFile, ImageInfo, JsonWebKey, MediaSource,
|
EncryptedFile, JsonWebKey, MediaSource,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use crate::{serde::Base64, OwnedMxcUri};
|
use crate::{serde::Base64, OwnedMxcUri};
|
||||||
@ -108,10 +107,11 @@ impl FileEventContent {
|
|||||||
relates_to: Option<Relation>,
|
relates_to: Option<Relation>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let FileMessageEventContent { body, filename, source, info, message, file } = content;
|
let FileMessageEventContent { body, filename, source, info, message, file } = content;
|
||||||
|
let FileInfo { mimetype, size, .. } = info.map(|info| *info).unwrap_or_default();
|
||||||
|
|
||||||
let message = message.unwrap_or_else(|| MessageContent::plain(body));
|
let message = message.unwrap_or_else(|| MessageContent::plain(body));
|
||||||
let file = file.unwrap_or_else(|| {
|
let file = file.unwrap_or_else(|| {
|
||||||
FileContent::from_room_message_content(source, info.as_deref(), filename)
|
FileContent::from_room_message_content(source, filename, mimetype, size)
|
||||||
});
|
});
|
||||||
|
|
||||||
Self { message, file, relates_to }
|
Self { message, file, relates_to }
|
||||||
@ -167,16 +167,15 @@ impl FileContent {
|
|||||||
/// Create a new `FileContent` with the given media source, file info and filename.
|
/// Create a new `FileContent` with the given media source, file info and filename.
|
||||||
pub fn from_room_message_content(
|
pub fn from_room_message_content(
|
||||||
source: MediaSource,
|
source: MediaSource,
|
||||||
info: Option<impl Into<FileContentInfo>>,
|
|
||||||
filename: Option<String>,
|
filename: Option<String>,
|
||||||
|
mimetype: Option<String>,
|
||||||
|
size: Option<UInt>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let (url, encryption_info) = match source {
|
let (url, encryption_info) = source.into_extensible_content();
|
||||||
MediaSource::Plain(url) => (url, None),
|
let info =
|
||||||
MediaSource::Encrypted(file) => (file.url.clone(), Some(Box::new((&*file).into()))),
|
FileContentInfo::from_room_message_content(filename, mimetype, size).map(Box::new);
|
||||||
};
|
|
||||||
let info = FileContentInfo::from_room_message_content(info, filename).map(Box::new);
|
|
||||||
|
|
||||||
Self { url, encryption_info, info }
|
Self { url, encryption_info: encryption_info.map(Box::new), info }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the file is encrypted.
|
/// Whether the file is encrypted.
|
||||||
@ -208,51 +207,22 @@ impl FileContentInfo {
|
|||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `FileContentInfo` with the given file info and filename.
|
/// Create a new `FileContentInfo` with the given filename, mimetype and size.
|
||||||
///
|
///
|
||||||
/// Returns `None` if both parameters are `None`.
|
/// Returns `None` if all parameters are `None`.
|
||||||
pub fn from_room_message_content(
|
pub fn from_room_message_content(
|
||||||
info: Option<impl Into<FileContentInfo>>,
|
|
||||||
filename: Option<String>,
|
filename: Option<String>,
|
||||||
|
mimetype: Option<String>,
|
||||||
|
size: Option<UInt>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
if filename.is_none() && info.is_none() {
|
if filename.is_none() && mimetype.is_none() && size.is_none() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let mut info: Self = info.map(Into::into).unwrap_or_default();
|
Some(Self { name: filename, mimetype, size })
|
||||||
info.name = filename;
|
|
||||||
Some(info)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&AudioInfo> for FileContentInfo {
|
|
||||||
fn from(info: &AudioInfo) -> Self {
|
|
||||||
let AudioInfo { mimetype, size, .. } = info;
|
|
||||||
Self { mimetype: mimetype.to_owned(), size: size.to_owned(), ..Default::default() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&FileInfo> for FileContentInfo {
|
|
||||||
fn from(info: &FileInfo) -> Self {
|
|
||||||
let FileInfo { mimetype, size, .. } = info;
|
|
||||||
Self { mimetype: mimetype.to_owned(), size: size.to_owned(), ..Default::default() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&ImageInfo> for FileContentInfo {
|
|
||||||
fn from(info: &ImageInfo) -> Self {
|
|
||||||
let ImageInfo { mimetype, size, .. } = info;
|
|
||||||
Self { mimetype: mimetype.to_owned(), size: size.to_owned(), ..Default::default() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&VideoInfo> for FileContentInfo {
|
|
||||||
fn from(info: &VideoInfo) -> Self {
|
|
||||||
let VideoInfo { mimetype, size, .. } = info;
|
|
||||||
Self { mimetype: mimetype.to_owned(), size: size.to_owned(), ..Default::default() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The encryption info of a file sent to a room with end-to-end encryption enabled.
|
/// The encryption info of a file sent to a room with end-to-end encryption enabled.
|
||||||
///
|
///
|
||||||
/// To create an instance of this type, first create a `EncryptedContentInit` and convert it via
|
/// To create an instance of this type, first create a `EncryptedContentInit` and convert it via
|
||||||
@ -310,7 +280,7 @@ impl From<EncryptedContentInit> for EncryptedContent {
|
|||||||
|
|
||||||
impl From<&EncryptedFile> for EncryptedContent {
|
impl From<&EncryptedFile> for EncryptedContent {
|
||||||
fn from(encrypted: &EncryptedFile) -> Self {
|
fn from(encrypted: &EncryptedFile) -> Self {
|
||||||
let EncryptedFile { key, iv, hashes, v, .. } = encrypted.to_owned();
|
let EncryptedFile { key, iv, hashes, v, .. } = encrypted;
|
||||||
Self { key, iv, hashes, v }
|
Self { key: key.to_owned(), iv: iv.to_owned(), hashes: hashes.to_owned(), v: v.to_owned() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,25 +104,21 @@ impl ImageEventContent {
|
|||||||
thumbnail,
|
thumbnail,
|
||||||
caption,
|
caption,
|
||||||
} = content;
|
} = content;
|
||||||
|
let ImageInfo { height, width, mimetype, size, thumbnail_info, thumbnail_source, .. } =
|
||||||
|
info.map(|info| *info).unwrap_or_default();
|
||||||
|
|
||||||
let message = message.unwrap_or_else(|| MessageContent::plain(body));
|
let message = message.unwrap_or_else(|| MessageContent::plain(body));
|
||||||
let file = file.unwrap_or_else(|| {
|
let file = file.unwrap_or_else(|| {
|
||||||
FileContent::from_room_message_content(source, info.as_deref(), None)
|
FileContent::from_room_message_content(source, None, mimetype, size)
|
||||||
});
|
});
|
||||||
let image =
|
let image = image
|
||||||
image.or_else(|| info.as_deref().map(|info| Box::new(info.into()))).unwrap_or_default();
|
.or_else(|| ImageContent::from_room_message_content(width, height).map(Box::new))
|
||||||
let thumbnail = thumbnail
|
|
||||||
.or_else(|| {
|
|
||||||
info.as_deref()
|
|
||||||
.and_then(|info| {
|
|
||||||
ThumbnailContent::from_room_message_content(
|
|
||||||
info.thumbnail_source.as_ref(),
|
|
||||||
info.thumbnail_info.as_deref(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map(|thumbnail| vec![thumbnail])
|
|
||||||
})
|
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
let thumbnail = thumbnail.unwrap_or_else(|| {
|
||||||
|
ThumbnailContent::from_room_message_content(thumbnail_source, thumbnail_info)
|
||||||
|
.into_iter()
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
|
|
||||||
Self { message, file, image, thumbnail, caption, relates_to }
|
Self { message, file, image, thumbnail, caption, relates_to }
|
||||||
}
|
}
|
||||||
@ -165,26 +161,26 @@ impl ImageContent {
|
|||||||
Self { height: Some(height), width: Some(width) }
|
Self { height: Some(height), width: Some(width) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new `ImageContent` with the given optional width and height.
|
||||||
|
///
|
||||||
|
/// Returns `None` if both parameters are `None`.
|
||||||
|
pub(crate) fn from_room_message_content(
|
||||||
|
width: Option<UInt>,
|
||||||
|
height: Option<UInt>,
|
||||||
|
) -> Option<Self> {
|
||||||
|
if width.is_none() && height.is_none() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Self { width, height })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether this `ImageContent` is empty.
|
/// Whether this `ImageContent` is empty.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.height.is_none() && self.width.is_none()
|
self.height.is_none() && self.width.is_none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&ImageInfo> for ImageContent {
|
|
||||||
fn from(info: &ImageInfo) -> Self {
|
|
||||||
let ImageInfo { height, width, .. } = info;
|
|
||||||
Self { height: height.to_owned(), width: width.to_owned() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&ThumbnailInfo> for ImageContent {
|
|
||||||
fn from(info: &ThumbnailInfo) -> Self {
|
|
||||||
let ThumbnailInfo { height, width, .. } = info;
|
|
||||||
Self { height: height.to_owned(), width: width.to_owned() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Thumbnail content.
|
/// Thumbnail content.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
|
||||||
@ -208,13 +204,14 @@ impl ThumbnailContent {
|
|||||||
///
|
///
|
||||||
/// Returns `None` if no thumbnail was found.
|
/// Returns `None` if no thumbnail was found.
|
||||||
pub fn from_room_message_content(
|
pub fn from_room_message_content(
|
||||||
thumbnail_source: Option<&MediaSource>,
|
source: Option<MediaSource>,
|
||||||
thumbnail_info: Option<&ThumbnailInfo>,
|
info: Option<Box<ThumbnailInfo>>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
thumbnail_source.map(|thumbnail_source| {
|
source.map(|source| {
|
||||||
let file =
|
let ThumbnailInfo { height, width, mimetype, size } = *info.unwrap_or_default();
|
||||||
ThumbnailFileContent::from_room_message_content(thumbnail_source, thumbnail_info);
|
|
||||||
let image = thumbnail_info.map(|info| Box::new(info.into()));
|
let file = ThumbnailFileContent::from_room_message_content(source, mimetype, size);
|
||||||
|
let image = ImageContent::from_room_message_content(width, height).map(Box::new);
|
||||||
|
|
||||||
Self { file, image }
|
Self { file, image }
|
||||||
})
|
})
|
||||||
@ -259,18 +256,15 @@ impl ThumbnailFileContent {
|
|||||||
///
|
///
|
||||||
/// Returns `None` if no thumbnail was found.
|
/// Returns `None` if no thumbnail was found.
|
||||||
fn from_room_message_content(
|
fn from_room_message_content(
|
||||||
thumbnail_source: &MediaSource,
|
source: MediaSource,
|
||||||
thumbnail_info: Option<&ThumbnailInfo>,
|
mimetype: Option<String>,
|
||||||
|
size: Option<UInt>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match thumbnail_source {
|
let info =
|
||||||
MediaSource::Plain(url) => {
|
ThumbnailFileContentInfo::from_room_message_content(mimetype, size).map(Box::new);
|
||||||
Self::plain(url.to_owned(), thumbnail_info.map(|info| Box::new(info.into())))
|
match source.into_extensible_content() {
|
||||||
}
|
(url, None) => Self::plain(url, info),
|
||||||
MediaSource::Encrypted(file) => Self::encrypted(
|
(url, Some(encryption_info)) => Self::encrypted(url, encryption_info, info),
|
||||||
file.url.clone(),
|
|
||||||
(&**file).into(),
|
|
||||||
thumbnail_info.map(|info| Box::new(info.into())),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,11 +292,15 @@ impl ThumbnailFileContentInfo {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&ThumbnailInfo> for ThumbnailFileContentInfo {
|
/// Creates a new `ThumbnailFileContentInfo` with the given optional MIME type and size.
|
||||||
fn from(info: &ThumbnailInfo) -> Self {
|
///
|
||||||
let ThumbnailInfo { mimetype, size, .. } = info;
|
/// Returns `None` if both the mimetype and the size are `None`.
|
||||||
Self { mimetype: mimetype.to_owned(), size: size.to_owned() }
|
fn from_room_message_content(mimetype: Option<String>, size: Option<UInt>) -> Option<Self> {
|
||||||
|
if mimetype.is_none() && size.is_none() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Self { mimetype, size })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use js_int::UInt;
|
|||||||
use serde::{de, Deserialize, Serialize};
|
use serde::{de, Deserialize, Serialize};
|
||||||
|
|
||||||
#[cfg(feature = "unstable-msc3551")]
|
#[cfg(feature = "unstable-msc3551")]
|
||||||
use super::file::{EncryptedContent, FileContent};
|
use super::file::{EncryptedContent, EncryptedContentInit, FileContent};
|
||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
use super::{
|
use super::{
|
||||||
file::FileContentInfo,
|
file::FileContentInfo,
|
||||||
@ -55,6 +55,19 @@ pub enum MediaSource {
|
|||||||
Encrypted(Box<EncryptedFile>),
|
Encrypted(Box<EncryptedFile>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "unstable-msc3551")]
|
||||||
|
impl MediaSource {
|
||||||
|
pub(crate) fn into_extensible_content(self) -> (OwnedMxcUri, Option<EncryptedContent>) {
|
||||||
|
match self {
|
||||||
|
MediaSource::Plain(url) => (url, None),
|
||||||
|
MediaSource::Encrypted(encrypted_file) => {
|
||||||
|
let EncryptedFile { url, key, iv, hashes, v } = *encrypted_file;
|
||||||
|
(url, Some(EncryptedContentInit { key, iv, hashes, v }.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Custom implementation of `Deserialize`, because serde doesn't guarantee what variant will be
|
// Custom implementation of `Deserialize`, because serde doesn't guarantee what variant will be
|
||||||
// deserialized for "externally tagged"¹ enums where multiple "tag" fields exist.
|
// deserialized for "externally tagged"¹ enums where multiple "tag" fields exist.
|
||||||
//
|
//
|
||||||
|
@ -8,7 +8,7 @@ use crate::events::voice::VoiceContent;
|
|||||||
#[cfg(feature = "unstable-msc3246")]
|
#[cfg(feature = "unstable-msc3246")]
|
||||||
use crate::events::{
|
use crate::events::{
|
||||||
audio::AudioContent,
|
audio::AudioContent,
|
||||||
file::{FileContent, FileContentInfo},
|
file::{EncryptedContent, FileContent, FileContentInfo},
|
||||||
message::MessageContent,
|
message::MessageContent,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -84,10 +84,22 @@ impl AudioMessageEventContent {
|
|||||||
#[cfg(feature = "unstable-msc3246")]
|
#[cfg(feature = "unstable-msc3246")]
|
||||||
file: Some(FileContent::plain(
|
file: Some(FileContent::plain(
|
||||||
url.clone(),
|
url.clone(),
|
||||||
info.as_deref().map(|info| Box::new(info.into())),
|
info.as_deref().and_then(|info| {
|
||||||
|
FileContentInfo::from_room_message_content(
|
||||||
|
None,
|
||||||
|
info.mimetype.to_owned(),
|
||||||
|
info.size.to_owned(),
|
||||||
|
)
|
||||||
|
.map(Box::new)
|
||||||
|
}),
|
||||||
)),
|
)),
|
||||||
#[cfg(feature = "unstable-msc3246")]
|
#[cfg(feature = "unstable-msc3246")]
|
||||||
audio: Some(info.as_deref().map_or_else(AudioContent::default, Into::into)),
|
audio: Some(
|
||||||
|
info.as_deref()
|
||||||
|
.and_then(|info| info.duration)
|
||||||
|
.map(AudioContent::from_room_message_content)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
),
|
||||||
#[cfg(feature = "unstable-msc3245")]
|
#[cfg(feature = "unstable-msc3245")]
|
||||||
voice: None,
|
voice: None,
|
||||||
body,
|
body,
|
||||||
@ -103,7 +115,11 @@ impl AudioMessageEventContent {
|
|||||||
#[cfg(feature = "unstable-msc3246")]
|
#[cfg(feature = "unstable-msc3246")]
|
||||||
message: Some(MessageContent::plain(body.clone())),
|
message: Some(MessageContent::plain(body.clone())),
|
||||||
#[cfg(feature = "unstable-msc3246")]
|
#[cfg(feature = "unstable-msc3246")]
|
||||||
file: Some(FileContent::encrypted(file.url.clone(), (&file).into(), None)),
|
file: Some(FileContent::encrypted(
|
||||||
|
file.url.clone(),
|
||||||
|
EncryptedContent::from(&file),
|
||||||
|
None,
|
||||||
|
)),
|
||||||
#[cfg(feature = "unstable-msc3246")]
|
#[cfg(feature = "unstable-msc3246")]
|
||||||
audio: Some(AudioContent::default()),
|
audio: Some(AudioContent::default()),
|
||||||
#[cfg(feature = "unstable-msc3245")]
|
#[cfg(feature = "unstable-msc3245")]
|
||||||
@ -184,19 +200,24 @@ impl AudioInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create an `AudioInfo` from the given file info and audio info.
|
/// Create an `AudioInfo` from the given file info and audio info.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the `AudioInfo` would be empty.
|
||||||
#[cfg(feature = "unstable-msc3246")]
|
#[cfg(feature = "unstable-msc3246")]
|
||||||
pub fn from_extensible_content(
|
pub fn from_extensible_content(
|
||||||
file_info: Option<&FileContentInfo>,
|
file_info: Option<&FileContentInfo>,
|
||||||
audio: &AudioContent,
|
audio: &AudioContent,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
if file_info.is_none() && audio.is_empty() {
|
let (mimetype, size) = file_info
|
||||||
|
.map(|info| {
|
||||||
|
let FileContentInfo { mimetype, size, .. } = info;
|
||||||
|
(mimetype.to_owned(), size.to_owned())
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
let AudioContent { duration, .. } = audio;
|
||||||
|
|
||||||
|
if duration.is_none() && mimetype.is_none() && size.is_none() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let (mimetype, size) = file_info
|
|
||||||
.map(|info| (info.mimetype.to_owned(), info.size.to_owned()))
|
|
||||||
.unwrap_or_default();
|
|
||||||
let AudioContent { duration, .. } = audio;
|
|
||||||
|
|
||||||
Some(Self { duration: duration.to_owned(), mimetype, size })
|
Some(Self { duration: duration.to_owned(), mimetype, size })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,14 @@ impl FileMessageEventContent {
|
|||||||
#[cfg(feature = "unstable-msc3551")]
|
#[cfg(feature = "unstable-msc3551")]
|
||||||
file: Some(FileContent::plain(
|
file: Some(FileContent::plain(
|
||||||
url.clone(),
|
url.clone(),
|
||||||
info.as_deref().map(|info| Box::new(info.into())),
|
info.as_deref().and_then(|info| {
|
||||||
|
FileContentInfo::from_room_message_content(
|
||||||
|
None,
|
||||||
|
info.mimetype.to_owned(),
|
||||||
|
info.size.to_owned(),
|
||||||
|
)
|
||||||
|
.map(Box::new)
|
||||||
|
}),
|
||||||
)),
|
)),
|
||||||
body,
|
body,
|
||||||
filename: None,
|
filename: None,
|
||||||
@ -101,7 +108,10 @@ impl FileMessageEventContent {
|
|||||||
message[0].body.clone()
|
message[0].body.clone()
|
||||||
};
|
};
|
||||||
let filename = file.info.as_deref().and_then(|info| info.name.clone());
|
let filename = file.info.as_deref().and_then(|info| info.name.clone());
|
||||||
let info = file.info.as_deref().map(|info| Box::new(info.into()));
|
let info = file.info.as_deref().and_then(|info| {
|
||||||
|
FileInfo::from_extensible_content(info.mimetype.to_owned(), info.size.to_owned())
|
||||||
|
.map(Box::new)
|
||||||
|
});
|
||||||
let source = (&file).into();
|
let source = (&file).into();
|
||||||
|
|
||||||
Self { message: Some(message), file: Some(file), body, filename, source, info }
|
Self { message: Some(message), file: Some(file), body, filename, source, info }
|
||||||
@ -138,12 +148,16 @@ impl FileInfo {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "unstable-msc3551")]
|
/// Creates a `FileInfo` with the given optional mimetype and size.
|
||||||
impl From<&FileContentInfo> for FileInfo {
|
///
|
||||||
fn from(info: &FileContentInfo) -> Self {
|
/// Returns `None` if the `FileInfo` would be empty.
|
||||||
let FileContentInfo { mimetype, size, .. } = info;
|
#[cfg(feature = "unstable-msc3551")]
|
||||||
Self { mimetype: mimetype.to_owned(), size: size.to_owned(), ..Default::default() }
|
fn from_extensible_content(mimetype: Option<String>, size: Option<UInt>) -> Option<Self> {
|
||||||
|
if mimetype.is_none() && size.is_none() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Self { mimetype, size, ..Default::default() })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
use crate::events::{
|
use crate::events::{
|
||||||
file::FileContent,
|
file::{FileContent, FileContentInfo},
|
||||||
image::{ImageContent, ThumbnailContent},
|
image::{ImageContent, ThumbnailContent},
|
||||||
message::MessageContent,
|
message::MessageContent,
|
||||||
};
|
};
|
||||||
@ -89,17 +89,30 @@ impl ImageMessageEventContent {
|
|||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
file: Some(FileContent::plain(
|
file: Some(FileContent::plain(
|
||||||
url.clone(),
|
url.clone(),
|
||||||
info.as_deref().map(|info| Box::new(info.into())),
|
info.as_deref().and_then(|info| {
|
||||||
|
FileContentInfo::from_room_message_content(
|
||||||
|
None,
|
||||||
|
info.mimetype.to_owned(),
|
||||||
|
info.size,
|
||||||
|
)
|
||||||
|
.map(Box::new)
|
||||||
|
}),
|
||||||
)),
|
)),
|
||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
image: Some(Box::new(info.as_deref().map_or_else(ImageContent::default, Into::into))),
|
image: Some(Box::new(
|
||||||
|
info.as_deref()
|
||||||
|
.and_then(|info| {
|
||||||
|
ImageContent::from_room_message_content(info.width, info.height)
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)),
|
||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
thumbnail: info
|
thumbnail: info
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.and_then(|info| {
|
.and_then(|info| {
|
||||||
ThumbnailContent::from_room_message_content(
|
ThumbnailContent::from_room_message_content(
|
||||||
info.thumbnail_source.as_ref(),
|
info.thumbnail_source.to_owned(),
|
||||||
info.thumbnail_info.as_deref(),
|
info.thumbnail_info.to_owned(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map(|thumbnail| vec![thumbnail]),
|
.map(|thumbnail| vec![thumbnail]),
|
||||||
|
@ -91,17 +91,34 @@ impl VideoMessageEventContent {
|
|||||||
#[cfg(feature = "unstable-msc3553")]
|
#[cfg(feature = "unstable-msc3553")]
|
||||||
file: Some(FileContent::plain(
|
file: Some(FileContent::plain(
|
||||||
url.clone(),
|
url.clone(),
|
||||||
info.as_deref().map(|info| Box::new(info.into())),
|
info.as_deref().and_then(|info| {
|
||||||
|
FileContentInfo::from_room_message_content(
|
||||||
|
None,
|
||||||
|
info.mimetype.to_owned(),
|
||||||
|
info.size.to_owned(),
|
||||||
|
)
|
||||||
|
.map(Box::new)
|
||||||
|
}),
|
||||||
)),
|
)),
|
||||||
#[cfg(feature = "unstable-msc3553")]
|
#[cfg(feature = "unstable-msc3553")]
|
||||||
video: Some(Box::new(info.as_deref().map_or_else(VideoContent::default, Into::into))),
|
video: Some(Box::new(
|
||||||
|
info.as_deref()
|
||||||
|
.map(|info| {
|
||||||
|
VideoContent::from_room_message_content(
|
||||||
|
info.height,
|
||||||
|
info.width,
|
||||||
|
info.duration,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)),
|
||||||
#[cfg(feature = "unstable-msc3553")]
|
#[cfg(feature = "unstable-msc3553")]
|
||||||
thumbnail: info
|
thumbnail: info
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.and_then(|info| {
|
.and_then(|info| {
|
||||||
ThumbnailContent::from_room_message_content(
|
ThumbnailContent::from_room_message_content(
|
||||||
info.thumbnail_source.as_ref(),
|
info.thumbnail_source.to_owned(),
|
||||||
info.thumbnail_info.as_deref(),
|
info.thumbnail_info.to_owned(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map(|thumbnail| vec![thumbnail]),
|
.map(|thumbnail| vec![thumbnail]),
|
||||||
|
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
use super::{
|
use super::{
|
||||||
file::FileContent,
|
file::{FileContent, FileContentInfo},
|
||||||
image::{ImageContent, ThumbnailContent},
|
image::{ImageContent, ThumbnailContent},
|
||||||
message::MessageContent,
|
message::MessageContent,
|
||||||
};
|
};
|
||||||
@ -96,13 +96,20 @@ impl StickerEventContent {
|
|||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
message: Some(MessageContent::plain(body.clone())),
|
message: Some(MessageContent::plain(body.clone())),
|
||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
file: Some(FileContent::plain(url.clone(), Some(Box::new((&info).into())))),
|
file: Some(FileContent::plain(
|
||||||
|
url.clone(),
|
||||||
|
FileContentInfo::from_room_message_content(None, info.mimetype.clone(), info.size)
|
||||||
|
.map(Box::new),
|
||||||
|
)),
|
||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
image: Some(Box::new((&info).into())),
|
image: Some(Box::new(
|
||||||
|
ImageContent::from_room_message_content(info.width, info.height)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)),
|
||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
thumbnail: ThumbnailContent::from_room_message_content(
|
thumbnail: ThumbnailContent::from_room_message_content(
|
||||||
info.thumbnail_source.as_ref(),
|
info.thumbnail_source.clone(),
|
||||||
info.thumbnail_info.as_deref(),
|
info.thumbnail_info.clone(),
|
||||||
)
|
)
|
||||||
.map(|thumbnail| vec![thumbnail]),
|
.map(|thumbnail| vec![thumbnail]),
|
||||||
#[cfg(feature = "unstable-msc3552")]
|
#[cfg(feature = "unstable-msc3552")]
|
||||||
|
@ -105,25 +105,29 @@ impl VideoEventContent {
|
|||||||
thumbnail,
|
thumbnail,
|
||||||
caption,
|
caption,
|
||||||
} = content;
|
} = content;
|
||||||
|
let VideoInfo {
|
||||||
|
duration,
|
||||||
|
height,
|
||||||
|
width,
|
||||||
|
mimetype,
|
||||||
|
size,
|
||||||
|
thumbnail_info,
|
||||||
|
thumbnail_source,
|
||||||
|
..
|
||||||
|
} = info.map(|info| *info).unwrap_or_default();
|
||||||
|
|
||||||
let message = message.unwrap_or_else(|| MessageContent::plain(body));
|
let message = message.unwrap_or_else(|| MessageContent::plain(body));
|
||||||
let file = file.unwrap_or_else(|| {
|
let file = file.unwrap_or_else(|| {
|
||||||
FileContent::from_room_message_content(source, info.as_deref(), None)
|
FileContent::from_room_message_content(source, None, mimetype, size)
|
||||||
|
});
|
||||||
|
let video = video.unwrap_or_else(|| {
|
||||||
|
Box::new(VideoContent::from_room_message_content(height, width, duration))
|
||||||
|
});
|
||||||
|
let thumbnail = thumbnail.unwrap_or_else(|| {
|
||||||
|
ThumbnailContent::from_room_message_content(thumbnail_source, thumbnail_info)
|
||||||
|
.into_iter()
|
||||||
|
.collect()
|
||||||
});
|
});
|
||||||
let video =
|
|
||||||
video.or_else(|| info.as_deref().map(|info| Box::new(info.into()))).unwrap_or_default();
|
|
||||||
let thumbnail = thumbnail
|
|
||||||
.or_else(|| {
|
|
||||||
info.as_deref()
|
|
||||||
.and_then(|info| {
|
|
||||||
ThumbnailContent::from_room_message_content(
|
|
||||||
info.thumbnail_source.as_ref(),
|
|
||||||
info.thumbnail_info.as_deref(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.map(|thumbnail| vec![thumbnail])
|
|
||||||
})
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
Self { message, file, video, thumbnail, caption, relates_to }
|
Self { message, file, video, thumbnail, caption, relates_to }
|
||||||
}
|
}
|
||||||
@ -169,15 +173,17 @@ impl VideoContent {
|
|||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new `VideoContent` with the given optional height, width and duration.
|
||||||
|
pub(crate) fn from_room_message_content(
|
||||||
|
height: Option<UInt>,
|
||||||
|
width: Option<UInt>,
|
||||||
|
duration: Option<Duration>,
|
||||||
|
) -> Self {
|
||||||
|
Self { height, width, duration }
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether this `VideoContent` is empty.
|
/// Whether this `VideoContent` is empty.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.height.is_none() && self.width.is_none() && self.duration.is_none()
|
self.height.is_none() && self.width.is_none() && self.duration.is_none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&VideoInfo> for VideoContent {
|
|
||||||
fn from(info: &VideoInfo) -> Self {
|
|
||||||
let VideoInfo { height, width, duration, .. } = info;
|
|
||||||
Self { height: height.to_owned(), width: width.to_owned(), duration: duration.to_owned() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -9,7 +9,9 @@ use super::{
|
|||||||
audio::AudioContent,
|
audio::AudioContent,
|
||||||
file::FileContent,
|
file::FileContent,
|
||||||
message::{MessageContent, TryFromExtensibleError},
|
message::{MessageContent, TryFromExtensibleError},
|
||||||
room::message::{AudioMessageEventContent, MessageType, Relation, RoomMessageEventContent},
|
room::message::{
|
||||||
|
AudioInfo, AudioMessageEventContent, MessageType, Relation, RoomMessageEventContent,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The payload for an extensible voice message.
|
/// The payload for an extensible voice message.
|
||||||
@ -82,12 +84,15 @@ impl VoiceEventContent {
|
|||||||
relates_to: Option<Relation>,
|
relates_to: Option<Relation>,
|
||||||
) -> Result<Self, TryFromExtensibleError> {
|
) -> Result<Self, TryFromExtensibleError> {
|
||||||
let AudioMessageEventContent { body, source, info, message, file, audio, voice } = content;
|
let AudioMessageEventContent { body, source, info, message, file, audio, voice } = content;
|
||||||
|
let AudioInfo { duration, mimetype, size } = info.map(|info| *info).unwrap_or_default();
|
||||||
|
|
||||||
let message = message.unwrap_or_else(|| MessageContent::plain(body));
|
let message = message.unwrap_or_else(|| MessageContent::plain(body));
|
||||||
let file = file.unwrap_or_else(|| {
|
let file = file.unwrap_or_else(|| {
|
||||||
FileContent::from_room_message_content(source, info.as_deref(), None)
|
FileContent::from_room_message_content(source, None, mimetype, size)
|
||||||
});
|
});
|
||||||
let audio = audio.or_else(|| info.as_deref().map(Into::into)).unwrap_or_default();
|
let audio = audio
|
||||||
|
.or_else(|| duration.map(AudioContent::from_room_message_content))
|
||||||
|
.unwrap_or_default();
|
||||||
let voice = if let Some(voice) = voice {
|
let voice = if let Some(voice) = voice {
|
||||||
voice
|
voice
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user