ruwuma/crates/ruma-common/src/events/room/thumbnail_source_serde.rs
Jonas Platte d855ec33d6 identifiers: Update ToOwned implementations to use new types
… and a lot of changes that cascaded from that.
2022-04-20 10:39:36 +02:00

202 lines
6.4 KiB
Rust

//! De-/serialization functions for `Option<MediaSource>` objects representing a thumbnail source.
use serde::{
ser::{SerializeStruct, Serializer},
Deserialize, Deserializer,
};
use crate::OwnedMxcUri;
use super::{EncryptedFile, MediaSource};
/// Serializes a MediaSource to a thumbnail source.
pub fn serialize<S>(source: &Option<MediaSource>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if let Some(source) = source {
let mut st = serializer.serialize_struct("ThumbnailSource", 1)?;
match source {
MediaSource::Plain(url) => st.serialize_field("thumbnail_url", url)?,
MediaSource::Encrypted(file) => st.serialize_field("thumbnail_file", file)?,
}
st.end()
} else {
serializer.serialize_none()
}
}
/// Deserializes a thumbnail source to a MediaSource.
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<MediaSource>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
pub struct ThumbnailSourceJsonRepr {
thumbnail_url: Option<OwnedMxcUri>,
thumbnail_file: Option<Box<EncryptedFile>>,
}
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)))
}
}
}
#[cfg(test)]
mod tests {
use matches::assert_matches;
use serde::{Deserialize, Serialize};
use serde_json::json;
use crate::{
events::room::{EncryptedFileInit, JsonWebKeyInit, MediaSource},
mxc_uri,
serde::Base64,
};
#[derive(Clone, Debug, Deserialize, Serialize)]
struct ThumbnailSourceTest {
#[serde(flatten, with = "super", skip_serializing_if = "Option::is_none")]
source: Option<MediaSource>,
}
#[test]
fn deserialize_plain() {
let json = json!({ "thumbnail_url": "mxc://notareal.hs/abcdef" });
assert_matches!(
serde_json::from_value::<ThumbnailSourceTest>(json).unwrap(),
ThumbnailSourceTest { source: Some(MediaSource::Plain(url)) }
if url == "mxc://notareal.hs/abcdef"
);
}
#[test]
fn deserialize_encrypted() {
let json = json!({
"thumbnail_file": {
"url": "mxc://notareal.hs/abcdef",
"key": {
"kty": "oct",
"key_ops": ["encrypt", "decrypt"],
"alg": "A256CTR",
"k": "TLlG_OpX807zzQuuwv4QZGJ21_u7weemFGYJFszMn9A",
"ext": true
},
"iv": "S22dq3NAX8wAAAAAAAAAAA",
"hashes": {
"sha256": "aWOHudBnDkJ9IwaR1Nd8XKoI7DOrqDTwt6xDPfVGN6Q"
},
"v": "v2",
},
});
assert_matches!(
serde_json::from_value::<ThumbnailSourceTest>(json).unwrap(),
ThumbnailSourceTest { source: Some(MediaSource::Encrypted(file)) }
if file.url == "mxc://notareal.hs/abcdef"
);
}
#[test]
fn deserialize_none_by_absence() {
let json = json!({});
assert_matches!(
serde_json::from_value::<ThumbnailSourceTest>(json).unwrap(),
ThumbnailSourceTest { source: None }
);
}
#[test]
fn deserialize_none_by_null_plain() {
let json = json!({ "thumbnail_url": null });
assert_matches!(
serde_json::from_value::<ThumbnailSourceTest>(json).unwrap(),
ThumbnailSourceTest { source: None }
);
}
#[test]
fn deserialize_none_by_null_encrypted() {
let json = json!({ "thumbnail_file": null });
assert_matches!(
serde_json::from_value::<ThumbnailSourceTest>(json).unwrap(),
ThumbnailSourceTest { source: None }
);
}
#[test]
fn serialize_plain() {
let request = ThumbnailSourceTest {
source: Some(MediaSource::Plain(mxc_uri!("mxc://notareal.hs/abcdef").into())),
};
assert_eq!(
serde_json::to_value(&request).unwrap(),
json!({ "thumbnail_url": "mxc://notareal.hs/abcdef" })
);
}
#[test]
fn serialize_encrypted() {
let request = ThumbnailSourceTest {
source: Some(MediaSource::Encrypted(Box::new(
EncryptedFileInit {
url: mxc_uri!("mxc://notareal.hs/abcdef").to_owned(),
key: JsonWebKeyInit {
kty: "oct".to_owned(),
key_ops: vec!["encrypt".to_owned(), "decrypt".to_owned()],
alg: "A256CTR".to_owned(),
k: Base64::parse("TLlG_OpX807zzQuuwv4QZGJ21_u7weemFGYJFszMn9A").unwrap(),
ext: true,
}
.into(),
iv: Base64::parse("S22dq3NAX8wAAAAAAAAAAA").unwrap(),
hashes: [(
"sha256".to_owned(),
Base64::parse("aWOHudBnDkJ9IwaR1Nd8XKoI7DOrqDTwt6xDPfVGN6Q").unwrap(),
)]
.into(),
v: "v2".to_owned(),
}
.into(),
))),
};
assert_eq!(
serde_json::to_value(&request).unwrap(),
json!({
"thumbnail_file": {
"url": "mxc://notareal.hs/abcdef",
"key": {
"kty": "oct",
"key_ops": ["encrypt", "decrypt"],
"alg": "A256CTR",
"k": "TLlG_OpX807zzQuuwv4QZGJ21_u7weemFGYJFszMn9A",
"ext": true
},
"iv": "S22dq3NAX8wAAAAAAAAAAA",
"hashes": {
"sha256": "aWOHudBnDkJ9IwaR1Nd8XKoI7DOrqDTwt6xDPfVGN6Q"
},
"v": "v2",
},
})
);
}
#[test]
fn serialize_none() {
let request = ThumbnailSourceTest { source: None };
assert_eq!(serde_json::to_value(&request).unwrap(), json!({}));
}
}