pub mod all_seasons;
use chrono::serde::ts_seconds;
use chrono::{DateTime, Utc};
use serde::Deserialize;
use super::UserProfile;
#[cfg(feature = "achievements")]
use crate::achievement::Achievement;
use crate::types::{Elo, Phase, PhasePoints, Rank, RankedAndCasual};
#[cfg(feature = "weekly_races")]
use crate::weekly_race::result::WeeklyRaceResult;
#[cfg(feature = "achievements")]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserAchievements {
display: Box<[Achievement]>,
total: Box<[Achievement]>,
}
#[cfg(feature = "achievements")]
impl UserAchievements {
pub fn displayed(&self) -> &[Achievement] {
&self.display
}
pub fn total(&self) -> &[Achievement] {
&self.total
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserTimestamps {
#[serde(with = "ts_seconds")]
first_online: DateTime<Utc>,
#[serde(with = "ts_seconds")]
last_online: DateTime<Utc>,
#[serde(with = "ts_seconds")]
last_ranked: DateTime<Utc>,
}
impl UserTimestamps {
pub fn first_online(&self) -> DateTime<Utc> {
self.first_online
}
pub fn last_online(&self) -> DateTime<Utc> {
self.last_online
}
pub fn last_ranked(&self) -> DateTime<Utc> {
self.last_ranked
}
}
pub type Stat = RankedAndCasual<Option<u64>>;
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserStats {
best_time: Stat,
highest_win_streak: Stat,
current_win_streak: Stat,
played_matches: Stat,
playtime: Stat,
forfeits: Stat,
completions: Stat,
wins: Stat,
#[serde(rename = "loses")]
losses: Stat,
}
impl UserStats {
pub fn best_time(&self) -> &Stat {
&self.best_time
}
pub fn highest_win_streak(&self) -> &Stat {
&self.highest_win_streak
}
pub fn current_win_streak(&self) -> &Stat {
&self.current_win_streak
}
pub fn played_matches(&self) -> &Stat {
&self.played_matches
}
pub fn playtime(&self) -> &Stat {
&self.playtime
}
pub fn forfeits(&self) -> &Stat {
&self.forfeits
}
pub fn completions(&self) -> &Stat {
&self.completions
}
pub fn wins(&self) -> &Stat {
&self.wins
}
pub fn losses(&self) -> &Stat {
&self.losses
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserStatistics {
season: UserStats,
total: UserStats,
}
impl UserStatistics {
pub fn season(&self) -> &UserStats {
&self.season
}
pub fn total(&self) -> &UserStats {
&self.total
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserConnection {
id: Box<str>,
name: Box<str>,
}
impl UserConnection {
pub fn id(&self) -> &str {
&self.id
}
pub fn name(&self) -> &str {
&self.name
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserConnections {
#[serde(default)]
discord: Option<UserConnection>,
#[serde(default)]
twitch: Option<UserConnection>,
#[serde(default)]
youtube: Option<UserConnection>,
}
impl UserConnections {
pub fn discord(&self) -> Option<&UserConnection> {
self.discord.as_ref()
}
pub fn twitch(&self) -> Option<&UserConnection> {
self.twitch.as_ref()
}
pub fn youtube(&self) -> Option<&UserConnection> {
self.youtube.as_ref()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EloPointsInfo {
#[serde(rename = "eloRate")]
elo: Option<Elo>,
#[serde(rename = "eloRank")]
rank: Option<Rank>,
#[serde(alias = "phasePoint", alias = "point")]
points: PhasePoints,
}
impl EloPointsInfo {
pub fn elo(&self) -> Option<Elo> {
self.elo
}
pub fn rank(&self) -> Option<Rank> {
self.rank
}
pub fn points(&self) -> PhasePoints {
self.points
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PhaseInfo {
phase: Phase,
#[serde(flatten)]
info: EloPointsInfo,
}
#[cfg(test)]
impl PhaseInfo {
pub(crate) fn new(phase: Phase, elo: Elo, rank: Rank, points: PhasePoints) -> Self {
Self {
phase,
info: EloPointsInfo {
elo: Some(elo),
rank: Some(rank),
points,
},
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserSeasonOutcome {
last: EloPointsInfo,
highest: Option<Elo>,
lowest: Option<Elo>,
phases: Box<[PhaseInfo]>,
}
#[cfg(test)]
impl UserSeasonOutcome {
pub(crate) fn new(
last_elo: Elo,
last_rank: Rank,
last_points: PhasePoints,
highest_elo: Elo,
lowest_elo: Elo,
phases: impl IntoIterator<Item = PhaseInfo>,
) -> Self {
Self {
last: EloPointsInfo {
elo: Some(last_elo),
rank: Some(last_rank),
points: last_points,
},
highest: Some(highest_elo),
lowest: Some(lowest_elo),
phases: phases.into_iter().collect(),
}
}
}
impl UserSeasonOutcome {
pub fn last(&self) -> &EloPointsInfo {
&self.last
}
pub fn highest(&self) -> Option<&Elo> {
self.highest.as_ref()
}
pub fn lowest(&self) -> Option<&Elo> {
self.lowest.as_ref()
}
pub fn phases(&self) -> &[PhaseInfo] {
&self.phases
}
}
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserInfo {
#[serde(flatten)]
profile: UserProfile,
#[cfg(feature = "achievements")]
achievements: UserAchievements,
timestamp: UserTimestamps,
statistics: UserStatistics,
connections: UserConnections,
season_result: Option<UserSeasonOutcome>,
#[cfg(feature = "weekly_races")]
weekly_races: Box<[WeeklyRaceResult]>,
}
impl UserInfo {
pub fn profile(&self) -> &UserProfile {
&self.profile
}
#[cfg(feature = "achievements")]
pub fn achievements(&self) -> &UserAchievements {
&self.achievements
}
pub fn timestamps(&self) -> &UserTimestamps {
&self.timestamp
}
pub fn connections(&self) -> &UserConnections {
&self.connections
}
pub fn season_result(&self) -> Option<&UserSeasonOutcome> {
self.season_result.as_ref()
}
#[cfg(feature = "weekly_races")]
pub fn weekly_races(&self) -> &[WeeklyRaceResult] {
&self.weekly_races
}
}