opgg 0.1.0

Rust asynchronous client for accessing the hero statistics API provided by [OP.GG](https://op.gg).
Documentation
use std::fmt;

use serde::Deserialize;
use serde::Serialize;

pub mod champion;
pub mod client;
pub mod error;

pub use client::Client;
use serde::Deserializer;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum GameMode {
    #[default]
    Aram,
    Ranked,
}

impl GameMode {
    pub fn allows_position(self, position: ChampionPosition) -> bool {
        match self {
            Self::Aram => position == ChampionPosition::None,
            Self::Ranked => position != ChampionPosition::None,
        }
    }
}

impl From<String> for GameMode {
    fn from(mode: String) -> Self {
        match mode.to_ascii_lowercase().as_str() {
            "ranked" => Self::Ranked,
            _ => Self::Aram,
        }
    }
}

impl fmt::Display for GameMode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Aram => write!(f, "aram"),
            Self::Ranked => write!(f, "ranked"),
        }
    }
}

#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ChampionPosition {
    #[default]
    None,
    #[serde(rename = "TOP")]
    Top,
    #[serde(rename = "MID")]
    Mid,
    #[serde(rename = "JUNGLE")]
    Jungle,
    #[serde(rename = "SUPPORT")]
    Support,
    #[serde(rename = "ADC")]
    Adc,
}

impl From<String> for ChampionPosition {
    fn from(posit: String) -> Self {
        match posit.to_ascii_uppercase().as_str() {
            "TOP" => Self::Top,
            "JUNGLE" => Self::Jungle,
            "MID" => Self::Mid,
            "SUPPORT" => Self::Support,
            "ADC" => Self::Adc,
            _ => Self::None,
        }
    }
}

impl fmt::Display for ChampionPosition {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::None => write!(f, "none"),
            Self::Top => write!(f, "TOP"),
            Self::Mid => write!(f, "MID"),
            Self::Jungle => write!(f, "JUNGLE"),
            Self::Support => write!(f, "SUPPORT"),
            Self::Adc => write!(f, "ADC"),
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
// #[serde(rename_all = "UPPERCASE")]
pub enum ChampionRole {
    Unknown,    // 未知
    Mage,       // 法师
    Controller, // 控制
    Fighter,    // 战士
    Tank,       // 坦克
    Marksman,   // 射手
    Assassin,   // 刺客
    Slayer,     // 游击
}

impl ChampionRole {
    pub fn chinese(&self) -> String {
        match self {
            Self::Mage => "法师".to_string(),
            Self::Controller => "控制".to_string(),
            Self::Fighter => "战士".to_string(),
            Self::Tank => "坦克".to_string(),
            Self::Marksman => "射手".to_string(),
            Self::Assassin => "刺客".to_string(),
            Self::Slayer => "游击".to_string(),
            _ => "未知".to_string(),
        }
    }
}

impl From<&str> for ChampionRole {
    fn from(role: &str) -> Self {
        match role.to_uppercase().as_str() {
            "MAGE" => Self::Mage,
            "CONTROLLER" => Self::Controller,
            "FIGHTER" => Self::Fighter,
            "TANK" => Self::Tank,
            "MARKSMAN" => Self::Marksman,
            "ASSASSIN" => Self::Assassin,
            "SLAYER" => Self::Slayer,
            _ => Self::Unknown,
        }
    }
}

impl fmt::Display for ChampionRole {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Unknown => write!(f, "UNKNOWN"),
            Self::Mage => write!(f, "MAGE"),
            Self::Controller => write!(f, "FIGHTER"),
            Self::Fighter => write!(f, "FIGHTER"),
            Self::Tank => write!(f, "TANK"),
            Self::Marksman => write!(f, "MARKSMAN"),
            Self::Assassin => write!(f, "ASSASSIN"),
            Self::Slayer => write!(f, "SLAYER"),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct ChampionRoles(pub Vec<ChampionRole>);

impl<'de> Deserialize<'de> for ChampionRoles {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        //e.g.. "FIGHTER|ASSASSIN|SLAYER"
        let s = String::deserialize(deserializer)?;
        let mut roles = Vec::new();
        for part in s.split('|') {
            let role = ChampionRole::from(part);
            roles.push(role);
        }
        Ok(ChampionRoles(roles))
    }
}

impl fmt::Display for ChampionRoles {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut iter = self.0.iter();
        if let Some(first) = iter.next() {
            write!(f, "{}", first.chinese())?;
            for role in iter {
                write!(f, "|{}", role.chinese())?;
            }
        }
        Ok(())
    }
}