diff --git a/src/entities/attachment.rs b/src/entities/attachment.rs index ce2fbdd..e4f2f57 100644 --- a/src/entities/attachment.rs +++ b/src/entities/attachment.rs @@ -47,7 +47,9 @@ pub struct ImageDetails { } /// The type of media attachment. -#[derive(Debug, Deserialize, Clone, Copy, PartialEq)] +#[derive(Debug, Deserialize, Clone, PartialEq)] +// Deserialize "Other" trick from https://github.com/serde-rs/serde/issues/912#issuecomment-803097289 +#[serde(remote = "MediaType")] pub enum MediaType { /// An image. #[serde(rename = "image")] @@ -55,10 +57,52 @@ pub enum MediaType { /// A video file. #[serde(rename = "video")] Video, + /// An audio file. + #[serde(rename = "audio")] + Audio, /// A gifv format file. #[serde(rename = "gifv")] Gifv, /// Unknown format. #[serde(rename = "unknown")] Unknown, + /// Anything else + #[serde(skip_deserializing)] + Other(String), +} + +use std::str::FromStr; +use serde::de::{value, Deserializer, IntoDeserializer}; + +impl FromStr for MediaType { + type Err = value::Error; + + fn from_str(s: &str) -> Result { + Self::deserialize(s.into_deserializer()) + } +} + +impl<'de> Deserialize<'de> for MediaType { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + let s = String::deserialize(deserializer)?; + let deserialized = Self::from_str(&s).unwrap_or_else(|_| { + Self::Other(s) + }); + Ok(deserialized) + } +} + +#[cfg(test)] +mod tests { + use crate::entities::prelude::MediaType; + use serde_json::Value; + + #[test] + fn test_deserialize_media_type() { + assert_eq!(MediaType::Image, serde_json::from_value(Value::String("image".to_owned())).unwrap()); + assert_eq!(MediaType::Audio, serde_json::from_value(Value::String("audio".to_owned())).unwrap()); + assert_eq!(MediaType::Other("pleroma_weird_thing".to_string()), serde_json::from_value(Value::String("pleroma_weird_thing".to_owned())).unwrap()); + } }