events: Add custom Deserialize impls for MediaSource

This commit is contained in:
Jonas Platte 2022-03-28 14:55:33 +02:00 committed by Jonas Platte
parent 8afc3a1100
commit deea762b8e
2 changed files with 40 additions and 22 deletions

View File

@ -5,7 +5,7 @@
use std::collections::BTreeMap;
use js_int::UInt;
use serde::{Deserialize, Serialize};
use serde::{de, Deserialize, Serialize};
use crate::{
serde::{base64::UrlSafe, Base64},
@ -34,7 +34,7 @@ pub mod tombstone;
pub mod topic;
/// The source of a media file.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Serialize)]
#[allow(clippy::exhaustive_enums)]
pub enum MediaSource {
/// The MXC URI to the unencrypted media file.
@ -46,6 +46,30 @@ pub enum MediaSource {
Encrypted(Box<EncryptedFile>),
}
/// Custom implementation of `Deserialize`, because serde doesn't guarantee what variant will be
/// deserialized for "externally tagged"¹ enums where multiple "tag" fields exist.
///
/// ¹ https://serde.rs/enum-representations.html
impl<'de> Deserialize<'de> for MediaSource {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
pub struct MediaSourceJsonRepr {
url: Option<Box<MxcUri>>,
file: Option<Box<EncryptedFile>>,
}
match MediaSourceJsonRepr::deserialize(deserializer)? {
MediaSourceJsonRepr { url: None, file: None } => Err(de::Error::missing_field("url")),
// Prefer file if it is set
MediaSourceJsonRepr { file: Some(file), .. } => Ok(MediaSource::Encrypted(file)),
MediaSourceJsonRepr { url: Some(url), .. } => Ok(MediaSource::Plain(url)),
}
}
}
/// Metadata about an image.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]

View File

@ -1,9 +1,8 @@
//! De-/serialization functions for `Option<MediaSource>` objects representing a thumbnail source.
use serde::{
de::Deserializer,
ser::{SerializeStruct, Serializer},
Deserialize,
Deserialize, Deserializer,
};
use crate::MxcUri;
@ -32,25 +31,20 @@ pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<MediaSource>, D::Er
where
D: Deserializer<'de>,
{
Option::<ThumbnailSource>::deserialize(deserializer).map(|source| source.map(Into::into))
}
#[derive(Deserialize)]
pub struct ThumbnailSourceJsonRepr {
thumbnail_url: Option<Box<MxcUri>>,
thumbnail_file: Option<Box<EncryptedFile>>,
}
#[derive(Clone, Debug, Deserialize)]
enum ThumbnailSource {
/// The MXC URI to the unencrypted media file.
#[serde(rename = "thumbnail_url")]
Plain(Box<MxcUri>),
/// The encryption info of the encrypted media file.
#[serde(rename = "thumbnail_file")]
Encrypted(Box<EncryptedFile>),
}
impl From<ThumbnailSource> for MediaSource {
fn from(source: ThumbnailSource) -> Self {
match source {
ThumbnailSource::Plain(url) => Self::Plain(url),
ThumbnailSource::Encrypted(file) => Self::Encrypted(file),
match ThumbnailSourceJsonRepr::deserialize(deserializer)? {
ThumbnailSourceJsonRepr { thumbnail_url: None, thumbnail_file: None } => Ok(None),
// Prefer file if it is set
ThumbnailSourceJsonRepr { thumbnail_file: Some(file), .. } => {
Ok(Some(MediaSource::Encrypted(file)))
}
ThumbnailSourceJsonRepr { thumbnail_url: Some(url), .. } => {
Ok(Some(MediaSource::Plain(url)))
}
}
}