mcsr_ranked_api/user/info/
mod.rs1pub mod all_seasons;
2
3use chrono::serde::{ts_seconds, ts_seconds_option};
4use chrono::{DateTime, Utc};
5use serde::Deserialize;
6#[cfg(feature = "serialize")]
7use serde::Serialize;
8
9use super::UserProfile;
10#[cfg(feature = "achievements")]
11use crate::achievement::Achievement;
12use crate::types::{Elo, Phase, PhasePoints, Rank, RankedAndCasual};
13#[cfg(feature = "weekly_races")]
14use crate::weekly_race::result::WeeklyRaceResult;
15
16#[cfg(feature = "achievements")]
18#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
19#[cfg_attr(feature = "serialize", derive(Serialize))]
20#[serde(rename_all = "camelCase")]
21pub struct UserAchievements {
22 pub display: Box<[Achievement]>,
24 pub total: Box<[Achievement]>,
26}
27#[cfg(feature = "achievements")]
28impl UserAchievements {
29 pub fn displayed(&self) -> &[Achievement] {
31 &self.display
32 }
33 pub fn total(&self) -> &[Achievement] {
35 &self.total
36 }
37}
38
39#[cfg_attr(feature = "serialize", derive(Serialize))]
40#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
41#[serde(rename_all = "camelCase")]
42pub struct UserTimestamps {
43 #[serde(with = "ts_seconds")]
44 first_online: DateTime<Utc>,
45 #[serde(with = "ts_seconds")]
46 last_online: DateTime<Utc>,
47 #[serde(with = "ts_seconds")]
48 last_ranked: DateTime<Utc>,
49 #[serde(with = "ts_seconds_option")]
50 next_decay: Option<DateTime<Utc>>,
51}
52
53pub type Stat = RankedAndCasual<Option<u64>>;
55
56#[cfg_attr(feature = "serialize", derive(Serialize))]
58#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
59#[serde(rename_all = "camelCase")]
60pub struct UserStats {
61 pub best_time: Stat,
62 pub highest_win_streak: Stat,
63 pub current_win_streak: Stat,
64 pub played_matches: Stat,
65 pub playtime: Stat,
66 pub completion_time: Stat,
67 pub forfeits: Stat,
68 pub completions: Stat,
69 pub wins: Stat,
70 #[serde(rename = "loses")]
71 pub losses: Stat,
72}
73
74#[cfg_attr(feature = "serialize", derive(Serialize))]
76#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
77#[serde(rename_all = "camelCase")]
78pub struct UserStatistics {
79 pub season: UserStats,
80 pub total: UserStats,
81}
82
83#[cfg_attr(feature = "serialize", derive(Serialize))]
85#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
86#[serde(rename_all = "camelCase")]
87pub struct UserConnection {
88 pub id: Box<str>,
89 pub name: Box<str>,
90}
91
92#[cfg_attr(feature = "serialize", derive(Serialize))]
94#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
95#[serde(rename_all = "camelCase")]
96pub struct UserConnections {
97 #[serde(default)]
98 pub discord: Option<UserConnection>,
99 #[serde(default)]
100 pub twitch: Option<UserConnection>,
101 #[serde(default)]
102 pub youtube: Option<UserConnection>,
103}
104
105#[cfg_attr(feature = "serialize", derive(Serialize))]
106#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub struct EloPointsInfo {
109 #[serde(rename = "eloRate")]
110 pub elo: Option<Elo>,
111 #[serde(rename = "eloRank")]
112 pub rank: Option<Rank>,
113 #[serde(alias = "phasePoint", alias = "point")]
114 pub points: PhasePoints,
115}
116
117#[cfg_attr(feature = "serialize", derive(Serialize))]
118#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
119#[serde(rename_all = "camelCase")]
120pub struct PhaseInfo {
121 pub phase: Phase,
122 #[serde(flatten)]
123 pub info: EloPointsInfo,
124}
125#[cfg(test)]
126impl PhaseInfo {
127 pub(crate) fn new(phase: Phase, elo: Elo, rank: Rank, points: PhasePoints) -> Self {
128 Self {
129 phase,
130 info: EloPointsInfo {
131 elo: Some(elo),
132 rank: Some(rank),
133 points,
134 },
135 }
136 }
137}
138
139#[cfg_attr(feature = "serialize", derive(Serialize))]
141#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
142#[serde(rename_all = "camelCase")]
143pub struct UserSeasonOutcome {
144 pub last: EloPointsInfo,
145 pub highest: Option<Elo>,
146 pub lowest: Option<Elo>,
147 pub phases: Box<[PhaseInfo]>,
148}
149#[cfg(test)]
150impl UserSeasonOutcome {
151 pub(crate) fn new(
152 last_elo: Elo,
153 last_rank: Rank,
154 last_points: PhasePoints,
155 highest_elo: Elo,
156 lowest_elo: Elo,
157 phases: impl IntoIterator<Item = PhaseInfo>,
158 ) -> Self {
159 Self {
160 last: EloPointsInfo {
161 elo: Some(last_elo),
162 rank: Some(last_rank),
163 points: last_points,
164 },
165 highest: Some(highest_elo),
166 lowest: Some(lowest_elo),
167 phases: phases.into_iter().collect(),
168 }
169 }
170}
171
172impl UserSeasonOutcome {
173 pub fn phases(&self) -> &[PhaseInfo] {
175 &self.phases
176 }
177}
178
179#[cfg_attr(feature = "serialize", derive(Serialize))]
181#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
182#[serde(rename_all = "camelCase")]
183pub struct UserInfo {
184 #[serde(flatten)]
185 pub profile: UserProfile,
186 #[cfg(feature = "achievements")]
187 pub achievements: UserAchievements,
188 #[serde(rename = "timestamp")]
189 pub timestamps: UserTimestamps,
190 pub statistics: UserStatistics,
191 pub connections: UserConnections,
192 pub season_result: Option<UserSeasonOutcome>,
193 #[cfg(feature = "weekly_races")]
194 pub weekly_races: Box<[WeeklyRaceResult]>,
195}
196impl UserInfo {
197 pub fn weekly_races(&self) -> &[WeeklyRaceResult] {
199 &self.weekly_races
200 }
201}