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 std::collections::BTreeMap;
use js_int::UInt; use js_int::UInt;
use serde::{Deserialize, Serialize}; use serde::{de, Deserialize, Serialize};
use crate::{ use crate::{
serde::{base64::UrlSafe, Base64}, serde::{base64::UrlSafe, Base64},
@ -34,7 +34,7 @@ pub mod tombstone;
pub mod topic; pub mod topic;
/// The source of a media file. /// The source of a media file.
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Serialize)]
#[allow(clippy::exhaustive_enums)] #[allow(clippy::exhaustive_enums)]
pub enum MediaSource { pub enum MediaSource {
/// The MXC URI to the unencrypted media file. /// The MXC URI to the unencrypted media file.
@ -46,6 +46,30 @@ pub enum MediaSource {
Encrypted(Box<EncryptedFile>), 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. /// Metadata about an image.
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)] #[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. //! De-/serialization functions for `Option<MediaSource>` objects representing a thumbnail source.
use serde::{ use serde::{
de::Deserializer,
ser::{SerializeStruct, Serializer}, ser::{SerializeStruct, Serializer},
Deserialize, Deserialize, Deserializer,
}; };
use crate::MxcUri; use crate::MxcUri;
@ -32,25 +31,20 @@ pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<MediaSource>, D::Er
where where
D: Deserializer<'de>, 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)] match ThumbnailSourceJsonRepr::deserialize(deserializer)? {
enum ThumbnailSource { ThumbnailSourceJsonRepr { thumbnail_url: None, thumbnail_file: None } => Ok(None),
/// The MXC URI to the unencrypted media file. // Prefer file if it is set
#[serde(rename = "thumbnail_url")] ThumbnailSourceJsonRepr { thumbnail_file: Some(file), .. } => {
Plain(Box<MxcUri>), Ok(Some(MediaSource::Encrypted(file)))
}
/// The encryption info of the encrypted media file. ThumbnailSourceJsonRepr { thumbnail_url: Some(url), .. } => {
#[serde(rename = "thumbnail_file")] Ok(Some(MediaSource::Plain(url)))
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),
} }
} }
} }