mcsr_ranked_api/user/info/
mod.rs

1pub 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/// Displayed and total achievements of a user
17#[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	/// Achievements the user chose to display on their profile
23	pub display: Box<[Achievement]>,
24	/// All of the user's achievements
25	pub total: Box<[Achievement]>,
26}
27#[cfg(feature = "achievements")]
28impl UserAchievements {
29	/// Achievements the user chose to display on their profile
30	pub fn displayed(&self) -> &[Achievement] {
31		&self.display
32	}
33	/// All of the user's achievements
34	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
53/// Single statistic in ranked and casual modes
54pub type Stat = RankedAndCasual<Option<u64>>;
55
56/// All of the user's statistics
57#[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/// All statistics for season and total
75#[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/// User's social connection
84#[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/// All of user's connections
93#[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/// Season result
140#[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	/// Every phase info
174	pub fn phases(&self) -> &[PhaseInfo] {
175		&self.phases
176	}
177}
178
179/// All of user's data combined
180#[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	/// User's weekly race stats
198	pub fn weekly_races(&self) -> &[WeeklyRaceResult] {
199		&self.weekly_races
200	}
201}