mcsr_ranked_api/user/info/
mod.rs1pub mod all_seasons;
2
3use chrono::serde::ts_seconds;
4use chrono::{DateTime, Utc};
5use serde::Deserialize;
6
7use super::UserProfile;
8#[cfg(feature = "achievements")]
9use crate::achievement::Achievement;
10use crate::types::{Elo, Phase, PhasePoints, Rank, RankedAndCasual};
11#[cfg(feature = "weekly_races")]
12use crate::weekly_race::result::WeeklyRaceResult;
13
14#[cfg(feature = "achievements")]
16#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
17#[serde(rename_all = "camelCase")]
18pub struct UserAchievements {
19 display: Box<[Achievement]>,
20 total: Box<[Achievement]>,
21}
22#[cfg(feature = "achievements")]
23impl UserAchievements {
24 pub fn displayed(&self) -> &[Achievement] {
26 &self.display
27 }
28 pub fn total(&self) -> &[Achievement] {
30 &self.total
31 }
32}
33
34#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
35#[serde(rename_all = "camelCase")]
36pub struct UserTimestamps {
37 #[serde(with = "ts_seconds")]
38 first_online: DateTime<Utc>,
39 #[serde(with = "ts_seconds")]
40 last_online: DateTime<Utc>,
41 #[serde(with = "ts_seconds")]
42 last_ranked: DateTime<Utc>,
43}
44impl UserTimestamps {
45 pub fn first_online(&self) -> DateTime<Utc> {
46 self.first_online
47 }
48 pub fn last_online(&self) -> DateTime<Utc> {
49 self.last_online
50 }
51 pub fn last_ranked(&self) -> DateTime<Utc> {
52 self.last_ranked
53 }
54}
55
56pub type Stat = RankedAndCasual<Option<u64>>;
58
59#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
61#[serde(rename_all = "camelCase")]
62pub struct UserStats {
63 best_time: Stat,
64 highest_win_streak: Stat,
65 current_win_streak: Stat,
66 played_matches: Stat,
67 playtime: Stat,
68 forfeits: Stat,
69 completions: Stat,
70 wins: Stat,
71 #[serde(rename = "loses")]
72 losses: Stat,
73}
74impl UserStats {
75 pub fn best_time(&self) -> &Stat {
76 &self.best_time
77 }
78
79 pub fn highest_win_streak(&self) -> &Stat {
80 &self.highest_win_streak
81 }
82
83 pub fn current_win_streak(&self) -> &Stat {
84 &self.current_win_streak
85 }
86
87 pub fn played_matches(&self) -> &Stat {
88 &self.played_matches
89 }
90
91 pub fn playtime(&self) -> &Stat {
92 &self.playtime
93 }
94
95 pub fn forfeits(&self) -> &Stat {
96 &self.forfeits
97 }
98
99 pub fn completions(&self) -> &Stat {
100 &self.completions
101 }
102
103 pub fn wins(&self) -> &Stat {
104 &self.wins
105 }
106
107 pub fn losses(&self) -> &Stat {
108 &self.losses
109 }
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
114#[serde(rename_all = "camelCase")]
115pub struct UserStatistics {
116 season: UserStats,
117 total: UserStats,
118}
119impl UserStatistics {
120 pub fn season(&self) -> &UserStats {
121 &self.season
122 }
123
124 pub fn total(&self) -> &UserStats {
125 &self.total
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
131#[serde(rename_all = "camelCase")]
132pub struct UserConnection {
133 id: Box<str>,
134 name: Box<str>,
135}
136impl UserConnection {
137 pub fn id(&self) -> &str {
138 &self.id
139 }
140
141 pub fn name(&self) -> &str {
142 &self.name
143 }
144}
145
146#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
148#[serde(rename_all = "camelCase")]
149pub struct UserConnections {
150 #[serde(default)]
151 discord: Option<UserConnection>,
152 #[serde(default)]
153 twitch: Option<UserConnection>,
154 #[serde(default)]
155 youtube: Option<UserConnection>,
156}
157impl UserConnections {
158 pub fn discord(&self) -> Option<&UserConnection> {
159 self.discord.as_ref()
160 }
161
162 pub fn twitch(&self) -> Option<&UserConnection> {
163 self.twitch.as_ref()
164 }
165
166 pub fn youtube(&self) -> Option<&UserConnection> {
167 self.youtube.as_ref()
168 }
169}
170
171#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct EloPointsInfo {
174 #[serde(rename = "eloRate")]
175 elo: Option<Elo>,
176 #[serde(rename = "eloRank")]
177 rank: Option<Rank>,
178 #[serde(alias = "phasePoint", alias = "point")]
179 points: PhasePoints,
180}
181impl EloPointsInfo {
182 pub fn elo(&self) -> Option<Elo> {
184 self.elo
185 }
186 pub fn rank(&self) -> Option<Rank> {
188 self.rank
189 }
190 pub fn points(&self) -> PhasePoints {
192 self.points
193 }
194}
195
196#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
197#[serde(rename_all = "camelCase")]
198pub struct PhaseInfo {
199 phase: Phase,
200 #[serde(flatten)]
201 info: EloPointsInfo,
202}
203#[cfg(test)]
204impl PhaseInfo {
205 pub(crate) fn new(phase: Phase, elo: Elo, rank: Rank, points: PhasePoints) -> Self {
206 Self {
207 phase,
208 info: EloPointsInfo {
209 elo: Some(elo),
210 rank: Some(rank),
211 points,
212 },
213 }
214 }
215}
216
217#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
219#[serde(rename_all = "camelCase")]
220pub struct UserSeasonOutcome {
221 last: EloPointsInfo,
222 highest: Option<Elo>,
223 lowest: Option<Elo>,
224 phases: Box<[PhaseInfo]>,
225}
226#[cfg(test)]
227impl UserSeasonOutcome {
228 pub(crate) fn new(
229 last_elo: Elo,
230 last_rank: Rank,
231 last_points: PhasePoints,
232 highest_elo: Elo,
233 lowest_elo: Elo,
234 phases: impl IntoIterator<Item = PhaseInfo>,
235 ) -> Self {
236 Self {
237 last: EloPointsInfo {
238 elo: Some(last_elo),
239 rank: Some(last_rank),
240 points: last_points,
241 },
242 highest: Some(highest_elo),
243 lowest: Some(lowest_elo),
244 phases: phases.into_iter().collect(),
245 }
246 }
247}
248
249impl UserSeasonOutcome {
250 pub fn last(&self) -> &EloPointsInfo {
252 &self.last
253 }
254 pub fn highest(&self) -> Option<&Elo> {
256 self.highest.as_ref()
257 }
258 pub fn lowest(&self) -> Option<&Elo> {
260 self.lowest.as_ref()
261 }
262 pub fn phases(&self) -> &[PhaseInfo] {
264 &self.phases
265 }
266}
267
268#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
270#[serde(rename_all = "camelCase")]
271pub struct UserInfo {
272 #[serde(flatten)]
273 profile: UserProfile,
274 #[cfg(feature = "achievements")]
275 achievements: UserAchievements,
276 timestamp: UserTimestamps,
277 statistics: UserStatistics,
278 connections: UserConnections,
279 season_result: Option<UserSeasonOutcome>,
280 #[cfg(feature = "weekly_races")]
281 weekly_races: Box<[WeeklyRaceResult]>,
282}
283impl UserInfo {
284 pub fn profile(&self) -> &UserProfile {
286 &self.profile
287 }
288 #[cfg(feature = "achievements")]
289 pub fn achievements(&self) -> &UserAchievements {
291 &self.achievements
292 }
293 pub fn timestamps(&self) -> &UserTimestamps {
295 &self.timestamp
296 }
297 pub fn connections(&self) -> &UserConnections {
299 &self.connections
300 }
301 pub fn season_result(&self) -> Option<&UserSeasonOutcome> {
303 self.season_result.as_ref()
304 }
305 #[cfg(feature = "weekly_races")]
306 pub fn weekly_races(&self) -> &[WeeklyRaceResult] {
308 &self.weekly_races
309 }
310}