reddit-rs 0.1.1

A wrapper around the Reddit API.
Documentation
use iri_string::types::IriAbsoluteString;
use serde::{de::Error, Deserialize, Serialize};
use serde_json::Value;

use crate::models::media::MediaThumbnail;

pub mod bandcamp;
pub mod gfycat;
pub mod imgur;
pub mod kickstarter;
pub mod quora;
pub mod soundcloud;
pub mod spotify;
pub mod streamable;
pub mod twitch;
pub mod twitter;
pub mod vimeo;
pub mod vimeo_player;
pub mod youtube;
pub mod youtube_mobile;

#[derive(Debug, Clone, Serialize, PartialEq)]
pub enum OEmbed {
    YouTube(OEmbedData<youtube::YouTube>),
    YouTubeMobile(OEmbedData<youtube_mobile::YouTubeMobile>),
    Streamable(OEmbedData<streamable::Streamable>),
    Gfycat(OEmbedData<gfycat::Gfycat>),
    Twitch(OEmbedData<twitch::Twitch>),
    Twitter(OEmbedData<twitter::Twitter>),
    Spotify(OEmbedData<spotify::Spotify>),
    Imgur(OEmbedData<imgur::Imgur>),
    Quora(OEmbedData<quora::Quora>),
    SoundCloud(OEmbedData<soundcloud::SoundCloud>),
    Vimeo(OEmbedData<vimeo::Vimeo>),
    VimeoPlayer(OEmbedData<vimeo_player::VimeoPlayer>),
    Kickstarter(OEmbedData<kickstarter::Kickstarter>),
    Bandcamp(OEmbedData<bandcamp::Bandcamp>),
}

impl<'de> Deserialize<'de> for OEmbed {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        #[derive(Debug, Deserialize)]
        struct Proxy {
            #[serde(rename = "type")]
            ty: String,
            oembed: Value,
        }

        let proxy = Proxy::deserialize(deserializer);
        let proxy = match proxy {
            Ok(proxy) => proxy,
            Err(why) => return Err(why),
        };

        let oembed = match proxy
            .ty
            .split_terminator('.')
            .collect::<Vec<_>>()
            .as_slice()
        {
            ["youtube", "com"] => {
                OEmbed::YouTube(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["m", "youtube", "com"] => OEmbed::YouTubeMobile(
                serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?,
            ),
            ["streamable", "com"] => {
                OEmbed::Streamable(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["gfycat", "com"] => {
                OEmbed::Gfycat(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["clips", "twitch", "tv"] => {
                OEmbed::Twitch(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["twitter", "com"] => {
                OEmbed::Twitter(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["open", "spotify", "com"] => {
                OEmbed::Spotify(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["imgur", "com"] => {
                OEmbed::Imgur(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["quora", "com"] => {
                OEmbed::Quora(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["soundcloud", "com"] => {
                OEmbed::SoundCloud(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["vimeo", "com"] => {
                OEmbed::Vimeo(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["kickstarter", "com"] => {
                OEmbed::Kickstarter(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            ["player", "vimeo", "com"] => {
                OEmbed::VimeoPlayer(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            [_, "bandcamp", "com"] => {
                OEmbed::Bandcamp(serde_json::from_value(proxy.oembed).map_err(D::Error::custom)?)
            }
            _ => {
                return Err(D::Error::invalid_value(
                    serde::de::Unexpected::Str(&proxy.ty),
                    &"one of theavailable oembed types",
                ))
            }
        };

        Ok(oembed)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OEmbedProvider {
    #[serde(rename = "provider_name")]
    pub name: String,
    #[serde(rename = "provider_url")]
    pub url: IriAbsoluteString,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct OEmbedData<T> {
    pub version: OEmbedVersion,

    #[serde(rename = "type")]
    pub ty: OEmbedType,

    #[serde(flatten)]
    pub thumbnail: Option<MediaThumbnail>,

    #[serde(flatten)]
    pub provider: OEmbedProvider,

    pub height: Option<u16>,
    pub width: u16,
    pub html: String,

    #[serde(flatten)]
    pub vendor_specific_data: T,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum OEmbedVersion {
    #[serde(rename = "1.0")]
    V1_0,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub enum OEmbedType {
    Video,
    Rich,
}