use std::collections::HashMap;
use super::find_rank;
use crate::data;
use crate::error::{ApiError, Result};
use crate::EndpointResult;
#[derive(serde_derive::Deserialize, Clone, Debug)]
#[doc(hidden)]
pub(crate) struct Response {
ok: i32,
count: u64,
list: Vec<ResponseRankedUser>,
users: HashMap<String, ExtendedUserInfo>,
}
#[derive(serde_derive::Deserialize, Clone, Hash, Debug)]
struct ResponseRankedUser {
rank: u32,
score: u64,
season: String,
user: String,
}
#[derive(serde_derive::Deserialize, Clone, Hash, Debug)]
struct ExtendedUserInfo {
_id: String,
username: String,
gcl: u64,
badge: data::Badge,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct LeaderboardPage {
pub total_count: u64,
pub ranks: Vec<RankedUser>,
#[serde(with = "::tuple_vec_map")]
pub user_details: Vec<(String, UserDetails)>,
_non_exhaustive: (),
}
pub type RankedUser = find_rank::FoundUserRank;
#[derive(Serialize, Deserialize, Clone, Hash, Debug)]
pub struct UserDetails {
pub user_id: String,
pub badge: data::Badge,
pub gcl_points: u64,
pub username: String,
_non_exhaustive: (),
}
impl EndpointResult for LeaderboardPage {
type RequestResult = Response;
type ErrorResult = data::ApiError;
fn from_raw(raw: Response) -> Result<LeaderboardPage> {
let Response {
ok,
count: total_count,
list,
users: user_details,
} = raw;
if ok != 1 {
return Err(ApiError::NotOk(ok).into());
}
Ok(LeaderboardPage {
total_count: total_count,
ranks: list
.into_iter()
.map(|info| RankedUser {
season_id: info.season,
user_id: info.user,
rank: info.rank,
raw_score: info.score,
_non_exhaustive: (),
})
.collect(),
user_details: user_details
.into_iter()
.map(|(user_id, data)| {
(
user_id,
UserDetails {
user_id: data._id,
badge: data.badge,
gcl_points: data.gcl,
username: data.username,
_non_exhaustive: (),
},
)
})
.collect(),
_non_exhaustive: (),
})
}
}
#[cfg(test)]
mod tests {
use super::LeaderboardPage;
use crate::EndpointResult;
use serde_json;
fn test_parse(json: serde_json::Value) {
let response = serde_json::from_value(json).unwrap();
let _ = LeaderboardPage::from_raw(response).unwrap();
}
#[test]
fn parse_sample_gcl() {
test_parse(json! ({
"count": 2322,
"list": [
{
"_id": "589125339c76d517f2424784",
"rank": 2,
"score": 408713655i64,
"season": "2017-02",
"user": "5769c4e64673b865097b926e"
},
{
"_id": "589125339c76d517f242475e",
"rank": 3,
"score": 362128212i64,
"season": "2017-02",
"user": "56dce30812162c1c122ae1b5"
}
],
"ok": 1,
"users": {
"56dce30812162c1c122ae1b5": {
"_id": "56dce30812162c1c122ae1b5",
"badge": {
"color1": "#511e00",
"color2": "#003058",
"color3": "#00450e",
"flip": true,
"param": -47,
"type": 1
},
"gcl": 2097651263i64,
"username": "taiga"
},
"5769c4e64673b865097b926e": {
"_id": "5769c4e64673b865097b926e",
"badge": {
"color1": "#000000",
"color2": "#000000",
"color3": "#430000",
"flip": false,
"param": 49,
"type": 8
},
"gcl": 1845096413i64,
"username": "Bovius"
}
}
}));
}
#[test]
fn parse_sample_power() {
test_parse(json! ({
"count": 60,
"list": [
{
"_id": "589125359c76d517f2424cea",
"rank": 2,
"score": 2653410i64,
"season": "2017-02",
"user": "567d9401f60a26fc4c41bd38"
},
{
"_id": "5891259a9c76d517f2427e9d",
"rank": 3,
"score": 2320123i64,
"season": "2017-02",
"user": "576aa0ce36db3b70321317fe"
}
],
"ok": 1,
"users": {
"567d9401f60a26fc4c41bd38": {
"_id": "567d9401f60a26fc4c41bd38",
"badge": {
"color1": 73,
"color2": 31,
"color3": 8,
"flip": false,
"param": 68,
"type": 10
},
"gcl": 2993541124i64,
"username": "bonzaiferroni"
},
"576aa0ce36db3b70321317fe": {
"_id": "576aa0ce36db3b70321317fe",
"badge": {
"color1": "#f9a603",
"color2": "#f7efe2",
"color3": "#f25c00",
"flip": false,
"param": 0,
"type": 9
},
"gcl": 1982028763i64,
"username": "Atavus"
}
}
}));
}
}