use serde::{self, Serialize, Deserialize};
use crate::traits::{PropLimRouteable, PropLimFetchable};
use crate::serde::one_default;
use std::ops::{Deref, DerefMut};
use crate::util::fetch_route;
use crate::error::Result;
#[cfg(feature = "async")]
use async_trait::async_trait;
#[cfg(feature = "async")]
use crate::util::a_fetch_route;
use crate::http::Client;
use crate::http::routes::Route;
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct ClubLeaderboard {
#[serde(default)]
pub items: Vec<ClubRanking>,
}
impl Deref for ClubLeaderboard {
type Target = Vec<ClubRanking>;
fn deref(&self) -> &Vec<ClubRanking> {
&self.items
}
}
impl DerefMut for ClubLeaderboard {
fn deref_mut(&mut self) -> &mut Vec<ClubRanking> {
&mut self.items
}
}
#[cfg_attr(feature = "async", async_trait)]
impl PropLimFetchable for ClubLeaderboard {
type Property = str;
type Limit = u8;
fn fetch(client: &Client, country_code: &str, limit: u8) -> Result<ClubLeaderboard> {
let route = ClubLeaderboard::get_route(country_code, limit);
fetch_route::<ClubLeaderboard>(client, &route)
}
#[cfg(feature="async")]
async fn a_fetch(
client: &Client, country_code: &'async_trait str, limit: u8
) -> Result<ClubLeaderboard>
where Self: 'async_trait,
Self::Property: 'async_trait,
{
let route = ClubLeaderboard::get_route(&country_code, limit);
a_fetch_route::<ClubLeaderboard>(client, &route).await
}
}
impl PropLimRouteable for ClubLeaderboard {
type Property = str;
type Limit = u8;
fn get_route(country_code: &str, limit: u8) -> Route {
Route::ClubRankings {
country_code: country_code.to_owned(),
limit
}
}
}
#[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ClubRanking {
#[serde(default)]
pub tag: String,
#[serde(default)]
pub name: String,
#[serde(default)]
pub trophies: usize,
#[serde(default = "one_default")]
pub rank: u8,
#[serde(default)]
pub member_count: usize,
}
impl Default for ClubRanking {
fn default() -> ClubRanking {
ClubRanking {
tag: String::from(""),
name: String::from(""),
trophies: 0,
rank: 1,
member_count: 0,
}
}
}
impl PartialOrd for ClubRanking {
fn partial_cmp(&self, other: &ClubRanking) -> Option<::std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ClubRanking {
fn cmp(&self, other: &ClubRanking) -> ::std::cmp::Ordering {
self.rank.cmp(&other.rank).reverse()
}
}
#[cfg(test)]
mod tests {
use serde_json;
use super::{ClubLeaderboard, ClubRanking};
use crate::error::Error;
#[test]
fn rankings_clubs_deser() -> Result<(), Box<dyn ::std::error::Error>> {
let rc_json_s = r##"{
"items": [
{
"tag": "#AAAAAAAAA",
"name": "Club",
"trophies": 30000,
"rank": 1,
"memberCount": 50
},
{
"tag": "#EEEEEEE",
"name": "Also Club",
"trophies": 25000,
"rank": 2,
"memberCount": 30
},
{
"tag": "#QQQQQQQ",
"name": "Clubby Club",
"trophies": 23000,
"rank": 3,
"memberCount": 25
},
{
"tag": "#55555553Q",
"name": "Not a valid club",
"trophies": 20000,
"rank": 4,
"memberCount": 10
}
]
}"##;
let c_leaders = serde_json::from_str::<ClubLeaderboard>(rc_json_s)
.map_err(Error::Json)?;
assert_eq!(
c_leaders,
ClubLeaderboard {
items: vec![
ClubRanking {
tag: String::from("#AAAAAAAAA"),
name: String::from("Club"),
member_count: 50,
trophies: 30000,
rank: 1,
},
ClubRanking {
tag: String::from("#EEEEEEE"),
name: String::from("Also Club"),
member_count: 30,
trophies: 25000,
rank: 2,
},
ClubRanking {
tag: String::from("#QQQQQQQ"),
name: String::from("Clubby Club"),
member_count: 25,
trophies: 23000,
rank: 3,
},
ClubRanking {
tag: String::from("#55555553Q"),
name: String::from("Not a valid club"),
member_count: 10,
trophies: 20000,
rank: 4,
}
]
}
);
Ok(())
}
}